BZOJ 4802 欧拉函数(素数判定Miller-Rabin+素因子分解Pollard-rho+欧拉函数)

50 篇文章 0 订阅

Description
给出一整数n,求phi
Input
一个正整数n(nM=1e18)
Output
输出phi(n)
Sample Input
8
Sample Output
4
Solution
用Pollard-rho对n素因子分解即可
Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=200001;
map<ll,int>factor;
map<ll,int>::iterator it;
vector<int>prime;
int is_prime[maxn];
void get_prime() 
{
    is_prime[0]=is_prime[1]=0;
    for(int i=2;i<maxn;i++)is_prime[i]=1;
    for(int i=2;i<maxn;i++) 
        if(is_prime[i]) 
        {
            prime.push_back(i);
            for(int j=2*i;j<maxn;j+=i)is_prime[j]=0;
        }
}
ll gcd(ll a,ll b)
{
    if(a==0)return 1;
    if(b==0)return a;
    return gcd(b,a%b);
}
ll Mul(ll a,ll b,ll p)
{
    return (a*b-(ll)(a/(ld)p*b+1e-3)*p+p)%p;
}
ll Pow(ll a,ll b,ll c)
{
    a%=c;
    ll ans=1;
    while(b)
    {
        if(b&1)ans=Mul(ans,a,c);
        a=Mul(a,a,c);
        b>>=1;
    }
    return ans;
}
bool Miller_Rabin(ll n,int times) 
{
    if(n<2)return 0;
    if(n==2)return 1;
    if(!(n&1))return 0;
    ll q=n-1;
    int k=0;
    while(q%2==0)k++,q>>=1;
    for(int i=0;i<times;i++) 
    {
        ll a=rand()%(n-1)+1;
        ll x=Pow(a,q,n);
        if(x==1)continue;
        bool found=0;
        for(int j=0;j<k;j++) 
        {
            if(x==n-1) 
            {
                found=1;
                break;
            }
            x=Mul(x,x,n);
        }
        if(found)continue;
        return 0;
    }
    return 1;
}
ll Pollard_rho(ll n,int c) 
{
    ll x=2,y=2,d=1;
    while(d==1) 
    {
        x=Mul(x,x,n)+c;
        y=Mul(y,y,n)+c;
        y=Mul(y,y,n)+c;
        d=gcd(abs(x-y),n);
    }
    if(d==n)return Pollard_rho(n,c+1);
    return d;
}
bool Is_Prime(ll n) 
{
    if(n<maxn)return is_prime[n];
    return Miller_Rabin(n,20);
}
void Find_Factor(ll n) 
{
    if(Is_Prime(n)) 
    {
        factor[n]++;
        return ;
    }
    else 
    {
        for(int i=0;i<prime.size();i++) 
            while(n%prime[i]==0) 
                factor[prime[i]]++,n/=prime[i];
        if(n!=1) 
        {
            if(Is_Prime(n))factor[n]++;
            else 
            {
                ll d=Pollard_rho(n,1);
                Find_Factor(d),Find_Factor(n/d);
            }
        }
    }
}
int main()
{
    ll n;
    scanf("%lld",&n);
    get_prime();
    factor.clear();
    Find_Factor(n);
    ll ans=n;
    for(it=factor.begin();it!=factor.end();it++)
        ans=ans/(it->first)*(it->first-1);
    printf("%lld\n",ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值