phi(大数质因数分解欧拉函数)

总结一下此题用的知识。。。
快速加,快速幂,素数判断(Miller_Rabin),gcd,Pollard_Rho。。。。
这里就写一个Pollard_Rho
对于一个大整数n,我们取任意一个数x使得x是n的质因数的几率很小,但如果取两个数x1以及x2使得它们的差是n的因数的几率就提高了(我也不会证明。。。。),如果取x1以及x2使得gcd(abs(x1−x2),n)>1的概率就更高了。这就是Pollard-Rho算法的主要思想。

对于满足gcd(abs(x1−x2),n)>1的x1和x2,gcd(abs(x1−x2),n)就是n的一个因数,只需要判断它是否为素数,若为素数,则是n的质因数,否则递归此过程。

其中判断素数就使用Miller-Rabin算法。

那么我们怎样不断取得x1和x2呢?
x1在区间[1,n]中随机(rand)出来,而x2则由x2=(x1*x1%n+c)%n推算出来,其中c为任意给定值,事实证明,这样就是比较优的。

#include
#include
#include
#define ll long long
using namespace std;
ll x,y,s[19999999],num;
ll multi(ll a,ll k,ll p){
    ll ans=0;
    while(k){
        if(k&1ll) ans=(a+ans)%p;a=(a+a)%p;k>>=1;
    }
    return ans;
}
ll qpow(ll a,ll k,ll p){
    ll ans=1;
    while(k){
        if(k&1ll) ans=multi(a,ans,p);a=multi(a,a,p);k>>=1;
    }
    return ans;
}
bool Miller_Rabin(ll n){
    if(n==2) return 1;
    ll u=n-1,t=0,s=20;
    while(!(u&1ll))
        t++,u>>=1;
    while(s--){
        ll a=rand()%(n-1)+1;
        x=qpow(a,u,n);
        for(int i=1;i<=t;i++){
            y=x,x=multi(x,x,n);
            if(x==1&&y!=1&&y!=n-1)return 0; 
        }if(x!=1) return 0;
    }   
    return 1;
}
ll gcd(ll a,ll b){
     return b?gcd(b,a%b):a;
}
ll Pollard_Rho(ll n,ll c){
    ll i=1,k=2,x=rand()%(n-1)+1,y=x;
    while(i++){
        x=(multi(x,x,n)+c)%n;
        ll p=gcd(y-x,n);
        if(p>1&&preturn p;
        if(x==y) return n;
        if(i==k) y=x,k<<=1;
    }
}
void find(ll n,ll c){
    if(n==1) return ;
    if(Miller_Rabin(n)) {
        s[++num]=n;return ;
    }
    ll p=n,k=c; 
    while(p==n) p=Pollard_Rho(n,c--);
    find(p,k);find(n/p,k);
}
ll N;
int main(){
    freopen("phi.in","r",stdin);
    freopen("phi.out","w",stdout);
    scanf("%lld",&N);
    find(N,99999);
    //for(int i=1;i<=num;i++) printf("%d ",s[i]);
    int t1=unique(s+1,s+num+1)-s-1; 

    for(int i=1;i<=t1;i++){
        N*=(s[i]-1);N/=s[i];    
    }
    printf("%lld",N);
}

你可能感兴趣的:(2016~2017)