[BZOJ 4802]欧拉函数(Pollard_rho+Miller_Rabin)
Description
已知N,求phi(N)
Solution
数据范围非常大所以分解质因数做,Pollard rho+Miller Rabin的板子
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<ctime> #include<map> using namespace std; typedef long long LL; LL ans; map<LL,bool>have; LL mul(LL a,LL b,LL p) { LL res=0; while(b) { if(b&1)res=(res+a)%p; a=(a+a)%p;b>>=1; } return res; } LL pow(LL a,LL n,LL p) { LL res=1; while(n) { if(n&1)res=mul(res,a,p); a=mul(a,a,p);n>>=1; } return res; } LL gcd(LL a,LL b) { return b?gcd(b,a%b):a; } bool check(LL a,LL m,LL n,LL cnt) { LL x=pow(a,m,n),y=x; for(int i=1;i<=cnt;i++) { x=mul(x,x,n); if(x==1&&y!=1&&y!=n-1)return 1; y=x; } return x!=1; } bool Miller_Rabin(LL n) { if(n==2)return 1; if(n&1==0||n<=1)return 0; LL m=n-1,cnt=0; while(m&1==0)cnt++,m>>=1; for(int i=1;i<=7;i++) { if(check(rand()%(n-1)+1,m,n,cnt)) return 0; } return 1; } LL rho(LL a,LL n,LL c) { LL i=1,k=2,x=a,y=x,d; while(1) { x=(mul(x,x,n)+c)%n; d=x>y?gcd(x-y,n):gcd(y-x,n); if(d>1)return d; if(x==y)return n; if(i==k)y=x,k<<=1; i++; } } void Pollard_rho(LL n) { if(n==1)return; if(Miller_Rabin(n)) { if(!have[n])ans=ans/n*(n-1); have[n]=1; return; } LL p=n; while(p==n)p=rho(rand()%(n-1)+1,n,rand()%(n-1)+1); Pollard_rho(p),Pollard_rho(n/p); } int main() { LL N; scanf("%lld",&N); ans=N; srand(299792458); Pollard_rho(N); printf("%lld\n",ans); return 0; }