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

来源:互联网 发布:胸口碎大石的网络意思 编辑:程序博客网 时间:2024/05/28 05:15
#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <vector>#include <algorithm>using namespace std;#define  LL __int64const 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 __int64const 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;}


原创粉丝点击