BZOJ 2818 Gcd
本题考查的知识点主要就是用线性筛法求欧拉函数φ,首先说一下什么是欧拉函数:对正整数n,欧拉函数是少于或等于n的数中与n互质的数的数目。之所以要用线性筛法,是因为它能使我们O(n)的求出值。
先简要介绍一下线性筛法求欧拉函数φ:(摘自baidu)
int m[maxn],phi[maxn],p[maxn],pt;//m[i]是i的最小素因数,p是素数,pt是素数个数 int make() { int k,N=maxn; phi[1]=1; for(int i=2;i<N;i++) { if(!m[i])//i是素数 { p[pt++]=m[i]=i; phi[i]=i-1; } for(int j=0;j<pt&&(k=p[j]*i)<N;j++) { m[k]=p[j]; if(m[i]==p[j])//为了保证以后的数不被再筛,要break { phi[k]=phi[i]*p[j]; /*这里的phi[k]与phi[i]后面的∏(p[i]-1)/p[i]都一样(m[i]==p[j])只差一个p[j],就可以保证∏(p[i]-1)/p[i]前面也一样了*/ break; } else { phi[k]=phi[i]*(p[j]-1);//积性函数性质,f(i*k)=f(i)*f(k) } } } }
之后就好做多了求出φ的前缀和乘2再减1,就好了,减得是(1,1)多算的。
这道题的代码如下:
#include<cstdio> #include<cstdlib> #include<iostream> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; const ll maxn=10000005; ll i_number,m; ll f[maxn],b[maxn],p[maxn]; int main() { cin>>i_number; f[1]=1; for(ll i=2;i<=i_number;i++) { if(!b[i]) { p[m++]=i; f[i]=i-1; } for(ll j=0;j<m&&p[j]*i<=i_number;j++) { f[p[j]*i]=f[i]*p[j]; b[p[j]*i]=1; if(!(i%p[j])) break; f[p[j]*i]=(p[j]-1)*f[i]; } } ll i_temp=0; for(ll i=1;i<=i_number;i++) { f[i]=f[i]+f[i-1]; } for(ll i=1;i<=i_number;i++) { f[i]=f[i]*2-1; } for(ll i=0;i<m;i++) { i_temp=i_temp+f[i_number/p[i]]; } cout<<i_temp<<endl; return 0; }