BZOJ 1968 [Ahoi2005]COMMON 约数研究
1968: [Ahoi2005]COMMON 约数研究
Description
Input
只有一行一个整数 N(0 < N < 1000000)。
Output
只有一行输出,为整数M,即f(1)到f(N)的累加和。
Sample Input
3
Sample Output
5
这一定是一道水题,当时因为这是练习积性函数的“好机会”,结果发现自己实在想得太复杂。0 < N < 1000000,因数不会超过这个界限,那么跑一遍就完了。代码也不用挂了。(52ms)
但我发现,也可以欧拉筛。(288 ms)
当然,还可使用区间乱跳,O(1)算出n div i为一定值的区间,而这种区间是O(sqrt(n))的。(0 ms)
1 /************************************************************** 2 Problem: 1968 3 User: Doggu 4 Language: C++ 5 Result: Accepted 6 Time:288 ms 7 Memory:13516 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 const int SIZE= 1000000; 12 int prime[SIZE], pri, n; 13 bool vis[SIZE+10]; 14 long long ans, tao[SIZE+10]; 15 void EULER(int upper_bound) { 16 tao[1]=1; 17 for( long long i = 2; i <= upper_bound; i++ ) { 18 if(!vis[i]) { 19 prime[++pri]=i; 20 tao[i]=2; 21 } 22 for( int t = 1; t <= pri; t++ ) { 23 long long j = i*prime[t]; 24 if(j>upper_bound) break; 25 vis[j]=1; 26 tao[j]=tao[i]*tao[prime[t]]; 27 if(i%prime[t]==0) { 28 long long a = i,tot=0; 29 while(a%prime[t]==0) a/=prime[t],tot++; 30 tao[j]=tao[a]*(tot+2); 31 break; 32 } 33 } 34 } 35 } 36 int main() { 37 scanf("%d",&n); 38 EULER(n+10); 39 for( int i = 1; i <= n; i++ ) ans+=tao[i]; 40 printf("%lld\n",ans); 41 return 0; 42 }