BZOJ_4802_欧拉函数_MR+pollard rho+欧拉函数

BZOJ_4802_欧拉函数_MR+pollard rho+欧拉函数

Description

已知N,求phi(N)

Input

正整数N。N<=10^18

Output

输出phi(N)

Sample Input

8

Sample Output

4

直接MR+Pollard rho分解质因数即可。具体可见https://www.cnblogs.com/suika/p/9127065.html
记得判重,我的map不知道为何T了。
 
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <map>
using namespace std;
typedef long long ll;
typedef double f2;
map<ll,int>mp;
ll ch(ll x,ll y,ll mod) {ll re=0;for(;y;y>>=1ll,x=(x+x)%mod) if(y&1ll) re=(re+x)%mod; return re;}
ll random(ll x,ll y) {return ((rand()*(1ll<<45))+(rand()*(1ll<<30))+(rand()<<15)+(rand()))%(y-x+1)+x;}
ll qp(ll x,ll y,ll mod) {ll re=1;for(;y;y>>=1ll,x=ch(x,x,mod)) if(y&1ll) re=ch(re,x,mod); return re;}
ll a[]={2,3,5,7,11,13,17,19,23,29};
ll ans;
ll Abs(ll x) {return x>0?x:-x;}
ll gcd(ll x,ll y) {return y?gcd(y,x%y):x;}
ll b[250000];
bool check(ll a,ll n,ll r,ll s) {
    ll x=qp(a,r,n),y=x,i;
    for(i=1;i<=s;i++,y=x) {x=ch(x,x,n); if(x==1&&y!=1&&y!=n-1) return 0;}
    return x==1;
} 
bool MR(ll n) {
    if(n<=1) return 0; ll r=n-1,s=0,i;
    for(;!(r&1);r>>=1ll,s++);
    for(i=0;i<=9;i++) {
        if(a[i]==n) return 1;
        if(!check(a[i],n,r,s)) return 0;
    }
    return 1;
}
ll f(ll x,ll c,ll mod) {return (ch(x,x,mod)+c)%mod;}
ll PR(ll n,ll c) {
    ll x=random(0,n-1),y=f(x,c,n),p;
    for(p=1;p==1&&x!=y;) {
        x=f(x,c,n); y=f(f(y,c,n),c,n); p=gcd(Abs(x-y),n);
    }
    return p==1?n:p;
    /*ll k=2,x=rand()%n,y=x,p=1,i;
    for(i=1;p==1;i++) {
        printf("%lld %lld\n",x,y);
        x=f(x,c,n); p=gcd(n,Abs(x-y)); if(i==k) y=x,k+=k;
    }
    return p;*/
}
void solve(ll n) {
    if(n==1) return ;
    if(MR(n)) {
        b[++b[0]]=n;
        return ; 
    }
    ll t=n;
    while(t==n) t=PR(n,rand()%n);
    solve(t); solve(n/t);
}
int main() {
    ll n;
    srand(19260817);
    scanf("%lld",&n); ans=n;
    int i;
    for(i=0;i<=9;i++) {
        if(n%a[i]==0) {
            ans=ans/a[i]*(a[i]-1); while(n%a[i]==0) n/=a[i];
        }
    }
    solve(n);
    int tot=unique(b+1,b+b[0]+1)-b-1;
    for(i=1;i<=tot;i++) ans=ans/b[i]*(b[i]-1); 
    printf("%lld\n",ans);
}

 

posted @ 2018-06-02 21:59  fcwww  阅读(209)  评论(0编辑  收藏  举报