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

来源:互联网 发布:与知乐差不多的作者 编辑:程序博客网 时间:2024/05/17 07:38

题意:在[1,c]和[1,d]中分别选两个数x,y,求gcd(x,y)==k的数的对数,其中(x,y)与(y,x)为同一种方案。

思路:假设c<d,在区间[1,c]可以直接用欧拉函数求解。然后枚举[c+1,d]的每个数,求在[1,c]中与这个数互质的数的个数,这个可以通过容斥原理解决。。。交完以后发现有好多0ms过掉的……上网翻了翻题解,貌似可以用莫比乌斯反演做?唉,慢慢学吧~


代码:

#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<map>#include<queue>#include<stack>#include<set>#include<cmath>#include<vector>#define inf 0x3f3f3f3f#define Inf 0x3FFFFFFFFFFFFFFFLL#define eps 1e-9#define pi acos(-1.0)using namespace std;typedef long long ll;const int maxn=100000+10;ll phi[maxn];void euler_table(){    phi[0]=0;phi[1]=1;    for(int i=2;i<maxn;++i) phi[i]=i;    for(int i=2;i<maxn;++i)    {        if(phi[i]==i)        {            for(int j=i;j<maxn;j+=i)                phi[j]=phi[j]-phi[j]/i;        }    }    for(int i=2;i<maxn;++i)        phi[i]+=phi[i-1];}int factor[20],tot,N;ll ans;void dfs(int pos,ll now,int sign){    ans+=N/now*sign;    for(int i=pos+1;i<tot;++i)        dfs(i,now*factor[i],-sign);}ll cal(int m,int n){    N=n;tot=0;ans=0;    int M=sqrt(m+0.5);    for(int i=2;i<=M;++i)    {        if(m%i==0)        {            factor[tot++]=i;            while(m%i==0) m/=i;        }    }    if(m>1) factor[tot++]=m;    for(int i=0;i<tot;++i)        dfs(i,factor[i],1);    return n-ans;}ll solve(int c,int d,int k){    if(k==0) return 0;    c/=k;d/=k;    if(c>d) swap(c,d);    ll res=phi[c];    for(int i=c+1;i<=d;++i)        res+=cal(i,c);    return res;}int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    int t,tcase=0,a,b,c,d,k;    euler_table();    scanf("%d",&t);    while(t--)    {        tcase++;        scanf("%d%d%d%d%d",&a,&c,&b,&d,&k);        printf("Case %d: %I64d\n",tcase,solve(c,d,k));    }    return 0;}

0 0