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; 
}

  

posted @ 2019-09-11 16:15  EM-LGH  阅读(139)  评论(0编辑  收藏  举报