欧拉函数小结

欧拉函数:小于等于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;
}

你可能感兴趣的:(欧拉函数小结)