[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
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/Zars19/p/6842763.html