我们先来看一下最经典的埃拉特斯特尼筛法。时间复杂度为O(n loglog n)
int ans[MAXN]; void Prime(int n) { int cnt=0; memset(prime,1,sizeof(prime)); prime[0]=prime[1]=0; for(int i=2;i<n;i++) { if(vis[i]) { ans[cnt++]=i;//保存素数 for(int j=i*i;j<n;j+=i)//i*i开始进行了稍微的优化 prime[j]=0;//不是素数 } } return ; }
由此,我们也可以发现有的合数被重复筛除,例如30,2*15筛了一次,5*6重复筛除,所以也就有了我们下面要提到的欧拉线性筛法。
不会重复筛除,是线性O(n)的复杂度。
const int MAXN=3000001; int prime[MAXN];//保存素数 bool vis[MAXN];//初始化 void Prime(int n) { int cnt=0; memset(vis,0,sizeof(vis)); for(int i=2;i<n;i++) { if(!vis[i]) prime[cnt++]=i; for(int j=0;j<cnt&&i*prime[j]<n;j++) { vis[i*prime[j]]=1; if(i%prime[j]==0)//关键 break; } } return cnt;//返回小于n的素数的个数 }首先,先明确一个条件,任何合数都能表示成一系列素数的积。
如果还不是很理解,可以手动模拟一下。
直接应用的一个简单例子。求n以内的素数个数。
http://blog.csdn.net/nk_test/article/details/46242311
欧拉函数:在数论中,对正整数n,欧拉函数是少于或等于n的数中与n互质的数的数目。
先给出一个结论:
设P是素数,
若p是x的约数,则E(x*p)=E(x)*p.
若p不是x的约数,则E(x*p)=E(x)*E(p)=E(x)*(p-1).
证明如下:
E(x)表示比x小的且与x互质的正整数的个数。
*若p是素数,E(p)=p-1。
*E(p^k)=p^k-p^(k-1)=(p-1)*P^(k-1)
证:令n=p^k,小于n的正整数数共有n-1即(p^k-1)个,其中与p不质的数共[p^(k-1)-1]个(分别为1*p,2*p,3*p...p(p^(k-1)-1))。
所以E(p^k)=(p^k-1)-(p^(k-1)-1)=p^k-p^(k-1).得证。
*若ab互质,则E(a*b)=E(a)*E(b),欧拉函数是积性函数.
*对任意数n都可以唯一分解成n=p1^a1*p2^a2*p3^a3*...*pn^an(pi为素数).
则E(n)=E(p1^a1)*E(p2^a2)*E(p3^a3)*...*E(pn^an)
=(p1-1)*p1^(a1-1)*(p2-1)*p2^(a2-1)*...*(pn-1)*pn^(an-1)
=(p1^a1*p2^a2*p3^a3*...*pn^an)*[(p1-1)*(p2-1)*(p3-1)*...*(pn-1)]/(p1*p2*p3*...*pn)
=n*(1-1/p1)*(1-1/p2)*...*(1-1/pn)
* E(p^k) =(p-1)*p^(k-1)=(p-1)*p^(k-2)*p
E(p^(k-1))=(p-1)*p^(k-2)
->当k>1时,E(p^k)=E(p*p^(k-1))=E(p^(k-1))*p.
(当k=1时,E(p)=p-1.)
由上式: 设P是素数,
若p是x的约数,则E(x*p)=E(x)*p.
若p不是x的约数,则E(x*p)=E(x)*E(p)=E(x)*(p-1). 证明结束。
http://acm.hdu.edu.cn/showproblem.php?pid=2824 具体的应用
求一段区间的欧拉函数的和。
#include<iostream> #include<string> #include<cstring> using namespace std; const int MAXN=3000001; int prime[MAXN];//保存素数 bool vis[MAXN];//初始化 int phi[MAXN];//欧拉函数 void Prime(int n) { int cnt=0; memset(vis,0,sizeof(vis)); for(int i=2;i<n;i++) { if(!vis[i]) { prime[cnt++]=i; phi[i]=i-1;// if p is prime,then phi[i]=i-1 } for(int j=0;j<cnt&&i*prime[j]<n;j++) { __int64 k=i*prime[j]; vis[k]=1; if(i%prime[j]==0)//关键 { phi[k]=phi[i]*prime[j]; break; } else phi[k]=phi[i]*(prime[j]-1); } } } int main() { int a,b; Prime(3000000); while(cin>>a>>b) { __int64 ans=0; for(int i=a;i<=b;i++) ans+=phi[i]; cout<<ans<<endl; } }
还有 http://acm.hdu.edu.cn/showproblem.php?pid=3501
分析:对于整数n,如果x(x<n)与n互质,那么(n-x)也与n是互质的;同理如果x(x<n)与n不互质,那么(n-x)也与n是不互质的。知道这个之后就可以得出:在0<x<n时,存在这样的x与n互质的个数假设为num(可以通过欧拉函数求得),那么所有与n互质的x的和sum=num*n/2.
/*利用欧拉函数即可求解,1~n比n小且与n互素的数的总和为 sum(n) = n * phi(n) / 2;那么可以先求出1~n-1的总和,然后 减去sum(n)即可。*/ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; #define MOD 1000000007 LL n; LL Eular(LL n) { LL cnt=1; for(int i=2; i*i<=n; i++) { if(n%i==0) { cnt*=(i-1); n/=i; while(n%i==0) { n/=i; cnt*=i; } } } if(n>1)cnt*=(n-1); return cnt; } int main() { while(~scanf("%lld",&n)&&n) { LL ans=(n+1)*n/2-n; ans-=Eular(n)*n/2; printf("%I64d\n",(ans%MOD+MOD)%MOD); } return 0; }
原文地址:http://blog.csdn.net/nk_test/article/details/46242401