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

题意:在[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;
}

你可能感兴趣的:(Math)