【Luogu】P2158仪仗队(欧拉函数)
首先来介绍欧拉函数。
设欧拉函数为f(n),则f(n)=1~n中与n互质的数的个数。
欧拉函数有三条引论:
1.若n为素数,则f(n)=n-1;
2.若n为pa,则f(n)=(p-1)*(pa-1)。
3.若gcd(a,b)=1,则f(a*b)=f(a)*f(b)。
下面代码给出欧拉函数的求法。可以和线性筛结合。
for(register int i=2;i<n;++i){ if(!f[i]){ prime[++num]=i; phi[i]=i-1; } for(int j=1;j<=num&&prime[j]*i<n;++j){ f[i*prime[j]]=1; if(!(i%prime[j])){ phi[i*prime[j]] = phi[i] * prime[j]; break; } phi[i*prime[j]]=phi[i]*(prime[j]-1); } }
phi数组是欧拉函数值。
那欧拉函数和本题有什么关系呢?
我们知道对于坐标点(i*k,j*k),它一定会被点(i,j)阻挡。
换句话说设i*k=a,j*k=b。
只要gcd(a,b)!=1则会被阻挡。
因此要求的是范围内满足条件gcd(a,b)=1的点(a,b)有多少个。
因为正方形关于对角线对称,所以可以只算左下部分,右上部分是和左下部分相等的。
因为是左下部分,所以a>=b。
原题变成了求∑phi(i),其中i=1~n。
代码如下。
#include<cstdio> #include<cctype> inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-'0'; ch=getchar(); } return num*f; } int prime[40010],num; bool f[40010]; bool d[40010]; int phi[40010]; int ans; int main(){ int n=read(); for(register int i=2;i<n;++i){ if(!f[i]){ prime[++num]=i; phi[i]=i-1; } for(int j=1;j<=num&&prime[j]*i<n;++j){ f[i*prime[j]]=1; if(!(i%prime[j])){ phi[i*prime[j]] = phi[i] * prime[j]; break; } phi[i*prime[j]]=phi[i]*(prime[j]-1); } } for(register int i=2;i<n;++i) ans+=phi[i]; printf("%d",ans*2+3); return 0; }