2 25608 24027
7680 16016
求约数 直接筛的裸算法过了。。
查题解发现有欧拉函数这个东西
在数论中,对正整数n,欧拉函数是小于或等于n的正整数中与n互质的数的数目。此函数以其首名研究者欧拉命名,它又称为φ函数、欧拉商数等。
因此 先打个素数表 求他是那些素数 然后直接用欧拉公式即可;
1.用约数筛
#include<stdio.h> #include<math.h> #include<string.h> int yueshu[200]; int yuenum; int ok[40000]; int ans=0; int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int CN,i,N,mem,j,t,k; while(scanf("%d",&CN)!=EOF) { for(i=1;i<=CN;i++) { memset(yueshu,0,sizeof(yueshu)); memset(ok,0,sizeof(ok)); yuenum=1; ans=0; scanf("%d",&mem); t=sqrt(mem); for(j=1;j<=t;j++) if(mem%j==0) { yueshu[yuenum++]=j; yueshu[yuenum++]=mem/j; } yuenum--; for(j=2;j<=yuenum;j++) { for(k=1;k*yueshu[j]<=mem;k++) ok[k*yueshu[j]]=1; } for(j=1;j<=mem;j++) if(ok[j]==0) ans++; printf("%d\n",ans); } } return 0; }2.O(n)级别素数筛选+欧拉
#include<stdio.h> int YNprime[40001]; int prime[40000]; int totprime=1; int get_prime(int maxn) { int i,j; for(i=2;i<=maxn;i++) { if(YNprime[i]==0) prime[totprime++]=i; for(j=1;i*prime[j]<=maxn&&j<totprime;j++) { YNprime[i*prime[j]]=1; if(i%prime[j]==0) break; } } } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); get_prime(40000); int CN,N,i,j,ans; while (scanf("%d",&CN)!=EOF) { for(i=1;i<=CN;i++) { scanf("%d",&N); ans=N; if(N==1) { printf("0\n");continue;} for(j=1;prime[j]<=N&&j<totprime;j++) { if(N%prime[j]==0) ans=(ans/prime[j])*(prime[j]-1); } printf("%d\n",ans); } } return 0; }
但有个更优美的代码:
用最小的素因子筛掉每个数 int prime[N],phi[N],cnt;// prime:记录质数,phi记录欧拉函数 int Min_factor[N];// i的最小素因子 bool vis[N]; void Init() { cnt=0; phi[1]=1; int x; for(int i=2;i<N;i++) { if(!vis[i]) { prime[++cnt]=i; phi[i]=i-1; Min_factor[i]=i; } for(int k=1;k<=cnt&&prime[k]*i<N;k++) { x=prime[k]*i; vis[x]=true; Min_factor[x]=prime[k]; if(i%prime[k]==0) { phi[x]=phi[i]*prime[k]; break; } else phi[x]=phi[i]*(prime[k]-1); } } }