BZOJ 4802: 欧拉函数 Pollard-Rho
这个东西太好用了,感觉很多题都可以用这个东西来写暴力或乱搞.
#include <set> #include <cmath> #include <ctime> #include <cstdio> #include <algorithm> #define ll long long #define ull unsigned long long #define setIO(s) freopen(s".in", "r" , stdin) using namespace std; set<ll>S; set<ll>::iterator it; int array[20]={2,3,5,7,11,13,17,19}; ll mult(ll x,ll y,ll mod) { ll tmp=(long double)x/mod*y; return ((ull)x*y-(ull)tmp*mod+mod)%mod; } ll F(ll a,ll c,ll mod) { return (mult(a,a,mod)+c)%mod; } ll qpow(ll base,ll k,ll mod) { ll tmp=1; for(;k;k>>=1,base=mult(base,base,mod)) if(k&1) tmp=mult(tmp,base,mod); return tmp; } int isprime(ll x) { if(x<=1) return 1; int k,i,j; ll cur=x-1,a,pre; for(k=0;cur%2==0;cur>>=1) ++k; for(i=0;i<8;++i) { if(array[i]==x) return 1; a=pre=qpow(array[i],cur,x); for(j=1;j<=k;++j) { a=mult(pre,pre,x); if(a==1&&pre!=1&&pre!=x-1) return 0; pre=a; } if(a!=1) return 0; } return 1; } ll pollard_rho(ll x) { int k,step; ll s=0,t=0,c=rand()%(x-1)+1,val=1,d; for(k=1;;k<<=1,s=t,val=1) { for(step=1;step<=k;++step) { t=F(t,c,x); val=mult(val,abs(t-s),x); if(step%127==0) { d=__gcd(val,x); if(d>1) return d; } } d=__gcd(val,x); if(d>1) return d; } } void solve(ll x) { if(x<2) return; if(isprime(x)) { S.insert(x); return; } ll p=x; for(;p>=x;) p=pollard_rho(x); for(;x%p==0;) x/=p; solve(x),solve(p); } int main() { // setIO("input"); ll n,ans=1; scanf("%lld",&n),solve(n); for(it=S.begin();it!=S.end();it++) { ll cur=(*it); for(;n%cur==0;) n/=cur,ans*=cur; ans=ans/cur*(cur-1); } printf("%lld\n",ans); return 0; }