HDU 1695 GCD#容斥原理

http://acm.hdu.edu.cn/showproblem.php?pid=1695

翻译题目:给五个数a,b,c,d,k,其中恒a=c=1,x∈[a,b],y∈[c,d],求有多少组(x,y)满足GCD(x,y)=k?  //(x,y)和(y,x)视作同一个

题解:既然是要x,y的最大公约数为k,那说明x/k和y/k是互质的,只需在[1,b/k]和[1,d/k]范围内找到适合的x,y即可。

特判:当k等于0时,显然没有符合的,输出结果0;

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;

vector<int> v;
ll solve(int l,int r,int n) //[l,r]内与n互素的数字个数
{
    v.clear();
    //筛选素数
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            v.push_back(i);
            while(n%i==0)
                n/=i;
        }
    }
    if(n>1)
        v.push_back(n);

    //容斥原理的二进制解法
    int len=v.size();
    ll res=0;
    for(int i=1;i<(1<<len);i++)
    {
        int cnt=0;
        ll val=1;
        for(int j=0;j<len;j++)
        {
            if(i&(1<<j))
            {
                cnt++;
                val*=v[j];
            }
        }
        if(cnt&1) //若为奇数项进行加法,偶数项进行减法
            res+=r/val-(l-1)/val;
        else res-=r/val-(l-1)/val;
    }
    return r-l+1-res;
}


int main()
{
    int t;
    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++)
    {
        int b,d,k;
        scanf("%*d%d%*d%d%d",&b,&d,&k);//默认a=c=1所以不必要输入a c
        if(k==0)
        {
            printf("Case %d: 0\n",cas);
            continue;
        }

        b/=k;d/=k;
        if(b>d) swap(b,d);
        ll ans=0;
        for(int i=1;i<=b;i++)
        {
            int tmp=i;
            ans+=solve(i,d,tmp);
        }
        printf("Case %d: %I64d\n",cas,ans);
    }
    return 0;
}
posted @ 2016-03-18 20:52  &ATM  阅读(206)  评论(0编辑  收藏  举报
……