欧拉函数
φ(n)
正常做法直接求
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
ll n,ans;
int main()
{
cin>>n;ans=n;
for(ll i=2;i*i<=n;i++)
{
{
while(n%i==0)n/=i;
ans=ans/i*(i-1);
}
}
if(n>1)
ans=ans/n*(n-1);
cout<<ans<<endl;
fclose(stdin);
fclose(stdout);
return 0;
}
恶心要求 n<=10^18
???
Miller Rabin+Pollard-rho!!
Miller Rabin判断大数是不是质数(随机算法)
Pollard-rho可以利用Miller Rabin求出质因数
如果当前的数不是质数,找质因数 再用 Pollard-rho 搜 n/d 和 d
如果是质数,由于具有不确定性,需要再去判断。
钟长者应该是想了一个晚上,最后也是说需要用 Pollard-rho,并扔下了一个链接
钟长者留的链接
(百度大法好)
//PS:太难了,不会 比着std写的
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<vector>
#include<map>
#include<string>
#include<iomanip>
#include<iostream>
#include<cmath>
#include<queue>
using namespace std;
#define ALL(x,S) for(x=S.begin();x!=S.end();x++)
typedef long long LL;
typedef long double real;
bool pd_prime[10010];
set<LL> S;
set<LL>::iterator pos;
LL n;
void pre()
{
int i,j;
memset(pd_prime,1,sizeof pd_prime);
pd_prime[1]=0;
for(int i=2;i<=10000;i++)
if(pd_prime[i])
for(int j=2;j<=10000/i;j++)
pd_prime[i*j]=0;
}
void addp(LL t)
{
S.insert(t);
}
LL gcd(LL a,LL b)
{
if(!b) return a;
return gcd(b,a%b);
}
LL mul(LL a,LL b,LL mod)
{
LL ans=0;
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;
while(b)
{
if(b&1) ans=mul(ans,a,mod);
b>>=1;
a=mul(a,a,mod);
}
return ans;
}
bool MR(LL n,LL k)
{
LL s=n-1,w=0;
while(!(s&1))
w++,s>>=1;
LL y=pow(k,s,n);
if(y==1 || y==n-1)
return 1;
while(w--)
{
y=mul(y,y,n);
if(y==n-1)
return 1;
}
return 0;
}
bool prime(LL n)
{
if(n<=10000)
return pd_prime[n];
bool flag=1;
for(int i=1;i<=50;i++)
if(pd_prime[i])
if(!MR(n,i)) flag=0;
return flag;
}
void rho(LL n)
{
if(n==1) return ;
if(n==4)
{
addp(2);
addp(2);
return ;
}
if(prime(n))
{
addp(n);
return ;
}
LL x,y,d,p;
while(1)
{
x=2,y=2,d=1;
p=mul(rand(),rand(),100000000);
if(d==1)
{
x=(mul(x,x,n)+p)%n;
y=(mul(y,y,n)+p)%n;
y=(mul(y,y,n)+p)%n;
d=gcd(abs(x-y),n);
}
if(d==n) continue;
rho(d);rho(n/d);
return ;
}
}
LL phi(LL x)
{
S.clear();
rho(x);
LL ans=x;
ALL(pos,S)
ans=ans/(*pos)*((*pos)-1);
return ans;
}
int main()
{
pre();
scanf("%lld",&n);
cout<<phi(n);
return 0;
}