题意:
就是求2~n的所有欧拉函数值的和,这里就用到了快速求欧拉函数的方法。(不能暴力求了,不然必定TLE啊)
说说欧拉筛法,感觉十分机智啊~~
对于上述代码的几个问题:
1.问:为什么i%prime==0时break?
答:欧拉筛法每次合成时都是用最小质因子合成的,如果我们在程序加一行记录,即可先行求出1~Maxn的最小质因子。这样避免不必要的重复,提高效率。
2.为什么当i%prime[j]==0时,phi[i*prime[j]]=phi[i]*prime[j]? 否则,phi[i*prime[j]]=phi[i]*(prime[j]-1)?
答:这是欧拉函数的几个性质哦,下面说说这个东西的证明。
欧拉函数的几个性质:E(x)表示比x小的且与x互质的正整数的个数。
1、*若p是素数,E(p)=p-1。
2、*E(p^k)=p^k - p^k /p = p* p^(k-1) - 1* p^(k-1) = (p-1)*p^(k-1)
证明如下:
最后一行有点难理解,解释一下:
假设a和b并不互质,b是质数,a是b的倍数。gcd(a,b)=b。E(a)和E(b)中都有一项(b-1)*b^0->(b-1),我们E(ab)的算式中间就有一项(b-1)*b,而E(a)和E(b)相乘后会变成(b-1)^2,所以在E(a)*E(b)的同时还要乘上b/b-1才能是结果正确,那么E(a*b)=E(a)*E(b)*b/b-1。因为b是质数,所以E(b)=b-1,所以有E(a*b)=E(a)*b。
因此,我们得到两个推论咯:
1、 当n为奇数时,E(2n)=E(n)
2、 当n是一个大于2的正整数时,E(n)是偶数
目前还没有发现这两个推论的用处,可以先记一记。不过上述两个性质是很重要哒~~~
这题的代码如下:
1 #include<cstdio> 2 #include<cstring> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<cmath> 7 using namespace std; 8 #define Maxn 1000000 9 #define LL long long 10 11 int phi[Maxn+10],prime[Maxn+10]; 12 LL h[Maxn+10]; 13 bool vis[Maxn+10]; 14 15 void ffind() 16 { 17 memset(vis,0,sizeof(vis)); 18 int len=0; 19 for(int i=2;i<=Maxn;i++) 20 { 21 if(!vis[i]) prime[++len]=i,phi[i]=i-1; 22 for(int j=1;j<=len;j++) 23 { 24 if(i*prime[j]>Maxn) break; 25 vis[i*prime[j]]=1; 26 if(i%prime[j]==0) 27 { 28 phi[i*prime[j]]=phi[i]*prime[j]; 29 break; 30 } 31 else phi[i*prime[j]]=phi[i]*(prime[j]-1); 32 } 33 } 34 h[1]=0; 35 for(int i=2;i<=Maxn;i++) h[i]=h[i-1]+phi[i]; 36 //for(int i=2;i<=20;i++) printf("%d:%d\n",i,phi[i]); 37 } 38 39 int main() 40 { 41 int n; 42 ffind(); 43 while(1) 44 { 45 scanf("%d",&n); 46 if(n==0) break; 47 printf("%lld\n",h[n]); 48 } 49 return 0; 50 }
poj24778
感觉这种题就是,看着别人的题解做,理解思路比打代码花的时间多了去了。数论一定要好好理解透彻啊~~
2016-02-04 16:42:48