题意与分析
感谢https://www.cnblogs.com/Leohh/p/7512960.html的题解。这题话说原来不在我的训练范围,正好有个同学问我,我就拿来做做。数学果然不是我擅长的啊,这么简单我都不会。。。
简单说下自己的理解。
从原题出发容易得到的朴素算法容易超时,所以要想到转化问题。原题要求1~n的因数之和,反过来说,就是求1~n中有几个数分别是1、2、…、n的倍数。这个弯子转过来,题目就容易写了。直接变成O(n)算法。
有趣的是,如果数据规模变为$10^{12}$,这道题该如何写呢?前面O(n)算法时,得到的式子是∑ni=1⌊ni⌋∑i=1n⌊ni⌋。容易发现,⌊ni⌋⌊ni⌋会对若干个连续的i相等。这个相等的i的区间是什么呢?考虑$n=ki+p$,p若想最接近0,k应当为⌊ni⌋⌊ni⌋,此时的imaximax即为⌊n⌊ni⌋⌋⌊n⌊ni⌋⌋。那么,直接让下个i变为imax+1imax+1即可。这段区间对答案的贡献是$(i_{max}−i_{origin}+1)∗k$。可以证明,这样的算法的复杂度是不同的$floor(n/i)$的个数,也就是$sqrt(n)$。
代码
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 #include <vector> 5 #define MP make_pair 6 #define PB push_back 7 #define fi first 8 #define se second 9 #define ZERO(x) memset((x), 0, sizeof(x)) 10 #define ALL(x) (x).begin(),(x).end() 11 #define rep(i, a, b) for (int i = (a); i <= (b); ++i) 12 #define per(i, a, b) for (int i = (a); i >= (b); --i) 13 #define QUICKIO 14 ios::sync_with_stdio(false); 15 cin.tie(0); 16 cout.tie(0); 17 using namespace std; 18 19 template<typename T> 20 T 21 read() 22 { 23 T tmp; cin>>tmp; 24 return tmp; 25 } 26 int ans[1000005]; 27 int 28 main() 29 { 30 ZERO(ans); 31 int n, tot=0; cin>>n; 32 rep(i, 1, n) 33 { 34 tot+=n/i; 35 } 36 cout<<tot<<endl; 37 return 0; 38 }