欧拉函数:小于等于n的与n互质的数。
求法:因为任何数都可以表示成n = p1^a1*p2^a2*·····pi^ai
可以推出eular(n)=n*(1-1/p1)*(1-1/p2)········(1-1/pi);
因为对于每一个质因子,比如2,那么在小于n的数中,与n不互质的,与其公约数是2的倍数的占其1/2,所以乘上1/2就是剩下与n公约数不含2的,然后依次类推,对于每个n的约数,乘上(pi-1/pi),最后的答案就是欧拉函数值了。
求单个欧拉函数:
int eular(int n)
{
int ret=n,a=n;
for(int i=2;i<=n;i++)
{
if(a%i==0)
{
ret=ret/i*(i-1);//先除防止溢出
while(a%i==0)
a/=i;
}
}
if(a>1)
ret=ret/a*(a-1);
return ret;
}
多个欧拉函数,打表,和素数筛差不多
const int maxn=1e7;
int phi[maxn];
int main()
{
for(int i=1;i<maxn;i++)
phi[i]=i;
for(int i=2;i<maxn;i+=2)
phi[i]/=2;
for(int i=3;i<maxn;i+=2)
{
if(phi[i]==i)
for(int j=i;j<maxn;j+=i)
phi[j]=phi[j]/i*(i-1);
}
hdu2824 http://acm.hdu.edu.cn/showproblem.php?pid=2824
连续的求和,打表省时间
#include <iostream>
using namespace std;
const int maxn = 3000001;
int phi[maxn];
void init()
{
for(int i=1;i<=maxn;i++)
phi[i]=i;
for(int i=2;i<=maxn;i+=2)
phi[i]/=2;
for(int i=3;i<=maxn;i+=2)
{
if(phi[i]==i)
for(int j=i;j<=maxn;j+=i)
phi[j]=phi[j]/i*(i-1);
}
}
int main()
{init();
int a,b;
long long sum;
while(cin>>a>>b)
{
sum=0;
for(int i=a;i<=b;i++)
sum+=phi[i];
cout<<sum<<endl;
}
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=1787
求小于n的gcd(i,n)大于1的个数,欧拉函数直接求gcd(i,n)==1的个数 用n减即可。
http://acm.hdu.edu.cn/showproblem.php?pid=3501
求小于n的与n不互质的数的和。
首先欧拉函数可以求出小于n的与n互质的数的个数,然后我们可以发现这样一个性质,当x与n互质时,n-x与n互质,那么所有小于n与n互质的数总是可以两两配对使其和为n,这也就是为什么当n大于2时欧拉函数都是偶数,知道这一点后,就可以计算出小于n与n互质的数的和了,那么不互质的和只要用总和来减就可以了。
#include <iostream>
using namespace std;
typedef long long LL;
LL eular(LL n)
{
LL ret=n,a=n;
for(LL i=2;i*i<=n;i++)
{
if(a%i==0)
ret=ret/i*(i-1);
while(a%i==0)
a/=i;
}
if(a>1)
ret=ret/a*(a-1);
return ret;
}
int main()
{LL n;
while(cin>>n&&n)
{
long long ans=n*(n+1)/2-n;
ans-=eular(n)*n/2;
cout<<ans%1000000007<<endl;
}
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=2588
求X满足1<=X<=N gcd (X,N)>=M
先求出N的约数,p1,p2····pi存起来,对于每一个大于等于M的约数,有gcd(k*pi,n)=pi>=M,即eular(n/pi)
#include <iostream>
#include <cstdio>
using namespace std;
int eular(int n)
{
int ret=n,a=n;
for(int i=2;i*i<=n;i++)
{
if(a%i==0)
ret=ret/i*(i-1);
while(a%i==0)
a/=i;
}
if(a>1)
ret=ret/a*(a-1);
return ret;
}
int main()
{int t,n,m;
int p[10000];
cin>>t;
while(t--)
{int ans=0,cnt=0,i;
scanf("%d%d",&n,&m);
for(i=1;i*i<n;i++)
if(n%i==0)
p[cnt++]=i,p[cnt++]=n/i;
if(n%i==0)
p[cnt++]=i;
for(i=0;i<cnt;i++)
if(p[i]>=m)
ans+=eular(n/p[i]);
printf("%d\n",ans);
}
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=4983
求满足gcd(n−a,n)*gcd(n−b,n)=n^k.
k>2时无解k=2时唯一解a=b=k
上式=gcd(a,n)*gcd(b,n)=n
k=1,枚举n的约数
#include <iostream>
using namespace std;
typedef long long LL;
const LL mod=1000000007;
LL eular(LL n)
{
LL ret=n,a=n;
for(LL i=2;i*i<=n;i++)
{
if(a%i==0)
ret=ret/i*(i-1);
while(a%i==0)
a/=i;
}
if(a>1)
ret=ret/a*(a-1);
return ret;
}
int main()
{int n,k;
while(cin>>n>>k)
{
if(n==1||k==2)
{cout<<"1"<<endl;continue;}
if(k>2)
{cout<<"0"<<endl;continue;}
LL ans=0;
for(LL i=1;i*i<=n;i++)
if(n%i==0)
{
LL t=eular(i)*eular(n/i)%mod;
(ans+=t)%=mod;
if(i*i!=n)
(ans+=t)%=mod;
}
cout<<ans<<endl;
}
return 0;
}