hdu 1695 GCD

题目:GCD   hdu 1695
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1695
题意:Given 5 integers: a, b, c, d, k, you're to find x in a...b, y in c...d that GCD(x, y) = k;给出abcdk五个数,求满足GCD(x, y) = k的x,y的种数。其中x满足在区间a...b内,y满足在区间c...d内;
解题思路:GCD(x, y) = k可以进行转换为GCD(x/k, y/k) = 1;在区间1...b/k与1...d/k内取小的那个求出在小一点的区间内互质的个数,再求在小区间内与大区间减去小区间的数中满足条件的个数。利用欧拉与容斥来进行两步的解决
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define LL long long
#define maxn 100005


int x[maxn],cnt[1005];


int euler_phi(int n)
{
    int m = (int)sqrt(n+0.5);
    int ans = n;
    for(int i = 2; i <= m; i++)
    {
        if(n%i==0)
        {
            ans = ans/i*(i-1);
            while(n%i==0)
                n/=i;
        }
    }
    if(n>1)
        ans = ans/n*(n-1);
    return ans;
}
LL Imco_prime(int n,int m)
{
    int i,j,t=0;
    for(i=2; i*i<=n; i++)
    {
        if(n&&n%i==0)
        {
            cnt[t++]=i;
            while(n&&n%i==0)
                n/=i;
        }
    }
    if(n>1)
        cnt[t++]=n;
    LL ans=0,tmp,flag;
    for(i=1; i<(1<<t); i++)
    {
        tmp=1,flag=0;
        for(j=0; j<t; j++)
            if(i&(1<<j))
                flag++,tmp*=cnt[j];
        if(flag&1)
            ans+=m/tmp;
        else
            ans-=m/tmp;
    }
    return ans;
}


int main()
{
    int T,t=0,a,b,c,d,k,i;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
        if(k==0)
        {
            printf("Case %d: 0\n",++t);
            continue;
        }
        b/=k,d/=k;
        if(b>d)
            swap(b,d);
        LL ans=0,tmp=(LL)b*(d-b);
        for(i=1; i<=b; i++)
            ans+=euler_phi(i);
        for(i=b+1; i<=d; i++)
            tmp-=Imco_prime(i,b);
        printf("Case %d: %I64d\n",++t,ans+tmp);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36979930/article/details/76409174