HDOJ 1695 GCD【欧拉函数+容斥原理】

Problem Description

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. GCD(x, y) means the greatest common divisor of x and y. Since the number of choices may be very large, you're only required to output the total number of different number pairs.
Please notice that, (x=5, y=7) and (x=7, y=5) are considered to be the same.
Yoiu can assume that a = c = 1 in all test cases.

 

Input

The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 3,000 cases.
Each case contains five integers: a, b, c, d, k, 0 < a <= b <= 100,000, 0 < c <= d <= 100,000, 0 <= k <= 100,000, as described above.

 

Output

For each test case, print the number of choices. Use the format in the example.

 

Sample Input

 

2 1 3 1 5 1 1 11014 1 14409 9

 

Sample Output

 

Case 1: 9 Case 2: 736427

Hint

For the first sample input, all the 9 pairs of numbers are (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 5), (3, 4), (3, 5).

题目翻译:已知区间【a,b】和【c,d】以及k,求有多少对gcd(x,y)==k ?其中x属于【a,b】,y属于【c,d】,为简化问题,a==c==1,注意gcd(2,3)和gcd(3,2)算一种情况

解题思路:转化问题之后,就是求[1,b/k]和[1,d/k]之间互质的数的对数,如果本题不考虑两个数字互换的情况,则就是典型的容斥原理,但是由于不可重复,则给题目加大了难度,假如b<d,则我们可以分两段来求,首先我们利用欧拉函数,求得n前有多少个数字与n互质,然后利用容斥原理求b+1到d中的任意数字与b之前的数字有多少互质!

#include<cstdio>
#define LL long long
const int Max=100005;
LL elur[Max];//存放每个数的欧拉函数值
int num[Max];//存放数的素因子个数
int p[Max][20];//存放数的素因子
void init(){//筛选法得到数的素因子及每个数的欧拉函数值
    elur[1]=1;
    for(int i=2;i<Max;i++){
        if(!elur[i]){
            for(int j=i;j<Max;j+=i){
                if(!elur[j])
                    elur[j]=j;
                elur[j]=elur[j]*(i-1)/i;
                p[j][num[j]++]=i;
            }
        }
        elur[i]+=elur[i-1]; //进行累加
    }
}
int nop(int n,int now,int t){
    int i;
    int ans=0;
    for(i=t;i<num[now];i++)
        ans+=n/p[now][i]-nop(n/p[now][i],now,i+1);
    return ans;
}
int main(){
    int t,T,a,b,c,d,k,i,j;
    init();
    scanf("%d",&T);
    for(t=1;t<=T;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){a=b;b=d;d=a;}
        LL ans=elur[b];
        for(i=b+1;i<=d;i++){
            ans+=b-nop(b,i,0);
        }
        printf("Case %d: %lld\n",t,ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值