【bzoj4802】欧拉函数 Pollard_Rho+Miller_Rabin

Description

已知N,求phi(N)
Input

正整数N。N<=10^18
Output

输出phi(N)
Sample Input

8
Sample Output

4
HINT

题解
https://www.cnblogs.com/galaxies/p/bzoj4802.html

模板

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define ll long long
#define inf 1000000000
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
ll n,pri[75];int m;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll Mul(ll a,ll b,ll mod)
{
    ll ans=0;a%=mod;
    while (b)
    {
        if (b&1) ans=(ans+a)%mod;
        a=(a+a)%mod;b>>=1;
    }
    return ans;
}
ll Pow(ll a,ll b,ll mod)
{
    ll ans=1;
    a%=mod;
    while (b)
    {
        if (b&1) ans=Mul(ans,a,mod);
        b>>=1;a=Mul(a,a,mod);
    }
    return ans;
}
bool Miller_Rabin(ll n)
{
    if (n==2) return 1;
    if (n<2||n%2==0) return 0;
    ll m=n-1,k=0;
    while (!(m&1)) m>>=1,k++;
    for (int i=0;i<10;i++)
    {
        ll a=rand()%(n-1)+1,x=Pow(a,m,n),y;
        for (int j=0;j<k;j++)
        {
            y=Mul(x,x,n);
            if (y==1&&x!=1&&x!=n-1) return 0;
            x=y;
        }
        if (x!=1) return 0;
    }
    return 1;
}
ll rnd(ll x,ll n,ll c)
{
    return (Mul(x,x,n)+c)%n;
}
ll Pollard_Rho(ll n,ll c)
{
    ll x,y;
    while (1)
    {
        x=rand()%(n-1)+1,y=rnd(x,n,c);
        while (1)
        {
            if (x==y) break;
            ll d=gcd(llabs(y-x)%n,n);
            if (d>1&&d<n) return d;
            x=rnd(x,n,c);
            y=rnd(rnd(y,n,c),n,c);
        }
        c=rand()%n;
    }
}
void decompose(ll n)
{
    if (n==1)return;
    if (Miller_Rabin(n)){pri[++m]=n;return;}
    ll p=Pollard_Rho(n,rand()%n);
    decompose(p);decompose(n/p);
}
int main()
{
    srand(19260817);
    scanf("%lld",&n);if (n==1) return puts("1"),0;
    if (Miller_Rabin(n)) return printf("%lld",n-1),0;
    decompose(n);
    sort(pri+1,pri+m+1);
    ll ans=pri[1]-1;
    for (int i=2;i<=m;i++)
        ans=ans*(pri[i]-(pri[i]!=pri[i-1]));
    cout<<ans;
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值