【HDU】 1695 GCD

来源:互联网 发布:类似snapseed的软件 编辑:程序博客网 时间:2024/06/06 00:57

GCD


题目链接

  • GCD

题目大意

现在给你两个区间:(a,b)和(c,d)现在让你在(a,b)中求出一个x,在(c,d)中求出一个y,满足gcd(x,y)=k,x,y颠倒的看作一组相同的答案(比如(1,2)和(2,1))


题解

首先看到gcd(a,b)=k,想到gcd(a/k,b/k)=1,转化为一个互质的问题。考虑到这点,我们把c和d都除k,这样我们只需要在(a,b),(c,d)中找到一组(x,y)满足互质就可以了。
到了这里,看到题目中数据较大,O(n2)的算法不考虑,我一开始想的是枚举x,然后用容斥原理在另外一个区间中算出与其互质的个数就行了,然而当我写完的时候,程序很不给情面地超时了….
后来看到题目给出了3000组测试数据,我需要不断计算(a,b)中数的因子3000次,于是想到了筛质数打表,然后竟然过了….
综上,筛质数加容斥原理。


代码

#include <iostream>#include <cstring>#include <cstdio>#include <cstdlib>#include <vector>using namespace std;int T,a,b,c,d,k,h;vector<int> p[100005];bool flag[100005];void deal(){    for (int i=0;i<=100000;i++) p[i].clear();    for (int i=2;i<=100000;i+=2) p[i].push_back(2);    for (int i=3;i<=100000;i+=2)    {        if (!flag[i]) for (int j=i;j<=100000;j+=i)        {            flag[j]=1;            p[j].push_back(i);        }    }}long long solve(int v,long long high){    long long t=1,l=0,sum=0;    for (long long i=1;i<(1<<p[v].size());i++)    {        t=1;l=0;        for (long long j=0;j<p[v].size();j++) if ((1<<j)&i)        {            t*=p[v][j];            l++;        }        if (l%2) sum+=high/t;        else sum-=high/t;    }    return high-sum;}int main(){    deal();    int Case=1;    long long ans=0;    scanf("%d",&T);    while (T--)    {        ans=0;        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);        printf("Case %d: ",Case++);        if (k==0)        {            printf("0\n");            continue;        }        b=b/k;        d=d/k;        if (b>d)        {            int p;            p=b; b=d; d=p;        }        for (int i=a;i<=b;i++) ans=ans+solve(i,d)-solv````````(i,i-1);        printf("%I64d\n",ans);    }    return 0;}
0 0