hdu 1695 GCD

您的好友急速上線發表於2017-07-31

題目: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;
}