hdu 1695 GCD 欧拉函数+容斥原理

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
#define  LL __int64
const LL maxn=1e5+10;
LL prime[maxn+10];
LL phi[maxn+10],vis[maxn+10],num[maxn+10];
vector<LL> e[maxn];
void phi_table()//求出所有的欧拉函数
{
    LL i,j;
    for(i=2;i<=maxn;i++)phi[i]=0;
    phi[1]=1;
    for(i=2;i<=maxn;i++)if(!phi[i])
        for(j=i;j<=maxn;j+=i)
        {
            if(!phi[j])
                phi[j]=j;
            phi[j]=phi[j]/i*(i-1);
        }
}
void sieve()
{
    LL i,j,m=(LL)sqrt(maxn+0.5);
    memset(vis,0,sizeof(vis));
    for(i=2;i<=m;i++)
    {
        if(!vis[i])
            for(j=i*i;j<=maxn;j+=i)vis[j]=1;
    }
}
void gen_primes()//求出素数表
{
    sieve();
    LL i,c=0;
    for(i=2;i<=maxn;i++)if(!vis[i])
        prime[c++]=i;
}
void init()     //初始化
{
    LL i,j,k;
    phi_table();
    gen_primes();
    for(i=1;i<maxn;i++)
    {
        k=i;
        for(j=0;prime[j]*prime[j]<=k;j++)
        {
            if(k%prime[j]==0)
            {
                e[i].push_back(prime[j]);//储存i的所有质因子
                while(k%prime[j]==0)
                    k/=prime[j];
            }
        }
        if(k>1)e[i].push_back(k);
    }
}
LL get_sum(LL a)//求a的二进制表示中1的个数,用于容斥法,奇加偶减
{
    LL s=0;
    while(a)
    {
        if(a&1)
            s++;
        a=a>>1;
    }
    return s;
}
LL dfs(LL a,LL b)//容斥法求1~b中与a不互质的个数
{
    LL t,i,j,k,ans=0,flag,s;
    t=e[a].size();
    for(i=1;i<(1<<t);i++)
    {

        if(get_sum(i)%2)flag=1;
        else flag=-1;
        s=1;
        for(j=0;j<t;j++)
        {
            if(i&(1<<j))s*=e[a][j];
        }
        ans+=flag*(b/s);
    }
    return ans;
}
int main()
{
    LL L,a,b,c,d,k,i,j,sum,tt=0,T;
    init();
    cin>>T;
    while(T--)
    {
        cin>>a>>b>>c>>d>>k;
        if(k==0||k>b||k>d)
        {
            cout<<"Case "<<++tt<<": 0"<<endl;
            continue;
        }
        if(b>d) swap(b,d);
        b/=k;
        d/=k;
        sum = 0;
        for(i=1;i<=b;i++)
            sum+=phi[i];
        for(i=b+1;i<=d;i++)
            sum+=b-dfs(i,b);
        cout<<"Case "<<++tt<<": "<<sum<<endl;
    }

    return 0;
}

/*
    本题简单化,a=c=1;
    所以只用求1~x和1~y中有多少对gcd(p,q)==1,其中1<=p<=x,1<=q<=y,x=b/k,y=d/k;
    因为如果gcd(p,q)==1,则gcd(p*k,q*k)==k(p*k<=b,q*k<=d)
    
    由于跟p,q顺序无关,所以交换使x>y,并令p>q,则当1<=p<=y,时(p,qi)的个数就是phi[p],欧拉函数,表示不大于p的与p互质的个数;
当y<p<=x,可以通过求1~y中有多少个数与p不互质,反求互质的个数。判断1~y中有多少个数与p不互质,由于1~y中的数如果是p的某个质因子倍数数,
则必定不互质,否则必定互质。因而可以用容斥原理求。(奇加偶减)
*/


简化版:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
#define  LL __int64
const LL maxn=1e5+10;
LL prime[maxn+10];
LL phi[maxn+10],vis[maxn+10],num[maxn+10];
LL e[maxn][7];
void init()     //初始化
{
    LL i,j;
    for(i=2;i<=maxn;i++)phi[i]=0;
    phi[1]=1;
    memset(num,0,sizeof(num));
    for(i=2;i<=maxn;i++)
    {
        if(!phi[i])
        {
            for(j=i;j<=maxn;j+=i)
            {
                if(!phi[j])
                    phi[j]=j;
                phi[j]=phi[j]/i*(i-1);
                e[j][num[j]++]=i;//这里不要用vector,会超时的
            }
        }
    }
}

LL dfs(LL a,LL b,LL c)//递归求容斥
{
    LL i,ans=0,t;
    for(i=a;i<num[c];i++)
    {
        t=b/e[c][i];
        ans+=t-dfs(i+1,t,c);
    }
    return ans;
}
int main()
{
    LL L,a,b,c,d,k,i,j,sum,tt=0,T;
    init();
    cin>>T;
    while(T--)
    {
        cin>>a>>b>>c>>d>>k;
        if(k==0||k>b||k>d)
        {
            cout<<"Case "<<++tt<<": 0"<<endl;
            continue;
        }
        if(b>d) swap(b,d);
        b/=k;
        d/=k;
        sum = 0;
        for(i=1;i<=b;i++)
            sum+=phi[i];
        for(i=b+1;i<=d;i++)
        {
            //sum+=b-dfs(i,b);
            sum+=b-dfs(0,b,i);
        }
        cout<<"Case "<<++tt<<": "<<sum<<endl;
    }

    return 0;
}



你可能感兴趣的:(欧拉函数,容斥原理)