HDU 1695-GCD(容斥)

来源:互联网 发布:飞雷神苦无淘宝 编辑:程序博客网 时间:2024/06/05 21:02

题目地址:HDU 1695
题意:在[1,b]和[1,d]中各选一个数x,y,使得GCD(x,y)=k,求满足的(x,y)对数,(x,y)和(y,x)算一种。
思路:GCD(x,y)=k 可以变换成GCD(x/k,y/k)=1。这也就变成了在[1,b/k]和[1,d/k]之间找到一个i,j,使得GCD[i,j]=1。因为(3,5)和(5,3)是同一种,所以我们让[1,b/k]为两个区间的小的区间,因为两个区间有相同的部分和不相同的部份,对于相同的部分按照容斥求完和之后/2,对于不同的部分直接按照容斥搞就好。注意K=0的情况。

#include <stdio.h>#include <math.h>#include <string.h>#include <stdlib.h>#include <iostream>#include <sstream>#include <algorithm>#include <set>#include <queue>#include <stack>#include <map>#include <bitset>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;typedef __int64 LL;const int inf=0x3f3f3f3f;const double pi= acos(-1.0);const double esp=1e-6;using namespace std;const int Maxn=101000;LL prime[Maxn];LL sprime[Maxn];bitset<Maxn>pri;LL k,cnt;void is_prime(){    pri.set();    for(LL i=2; i<Maxn; i++) {        if(pri[i]) {            prime[k++]=i;            for(LL j=i+i; j<Maxn; j+=i)                pri[j]=0;        }    }}void Divide(LL n){    cnt=0;    LL t=(LL)sqrt(1.0*n);    for(LL i=0; prime[i]<=t; i++) {        if(n%prime[i]==0) {            sprime[cnt++]=prime[i];            while(n%prime[i]==0)                n/=prime[i];        }    }    if(n>1)        sprime[cnt++]=n;}LL Ex(LL n){    LL ans=0;    LL tmp,flag;    LL i,j;    for(i=1; i<(LL)(1<<cnt); i++) {        tmp=1;        flag=0;        for(j=0; j<cnt; j++)            if(i&((LL)(1<<j))) {                flag++;                tmp*=sprime[j];            }        if(flag&1)            ans+=n/tmp;        else            ans-=n/tmp;    }    return ans;}int main(){    int T;    int icase=1;    LL a,b,c,d,k;    LL res;    is_prime();    scanf("%d",&T);    while(T--) {        res=0;        scanf("%lld %lld %lld %lld %lld",&a,&b,&c,&d,&k);        if(b>d) swap(b,d);        if(k==0){            printf("Case %d: 0\n",icase++);            continue;        }        b=b/k;        d=d/k;        for(LL i=1; i<=b; i++) {            Divide(i);            res+=b-Ex(b);        }        res=(res+1)/2;        for(LL j=b+1; j<=d; j++) {            Divide(j);            res+=b-Ex(b);        }        printf("Case %d: %lld\n",icase++,res);    }return 0;}
1 0
原创粉丝点击