HDU 1695 GCD 欧拉函数+容斥原理(难+好)

本文介绍了一种用于寻找给定范围内数对的最大公约数的算法,详细解释了求解过程并提供了代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


GCD

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4825    Accepted Submission(s): 1729


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).
 

Source

给你5个数,a,b,c,d,k在[a,b]区间找一个数x,在[c,d]区间找一个数y,使得(x,y)的最大公约数是k。找出所有满足条件的不同的(x,y)的对数。
要求两个集合(1...b, 1...d)中有多少对数的最大公约数为k,此问题等价于求两个集合(1...b/k,1...d/k)中有多少对数互质。假设b/k<d/k。
题目可以分两部分求解,第一部分就是求1~b之间有多少对数互质,即求欧拉函数。第二部分求b+1~d之间每一个数与1~b之间有多少数互质。对于(b+1~d)中的每一个y,要想知道(1~b)中有多少数与它互质,我们只需要知道多少个数与它不互质即可。而两个数不互质就意味着它们有公因子。对于每一个y的因子f,都能确定地知道(1~b)中有多少个数含有因子f,用容斥原理算一下,就能知道(1~b)中有多少个数与y互质了。
//171MS	9240K
#include<stdio.h>
#include<string.h>
#define M 100007
long long phi[M];
int prime[M][20],num[M];//prime[i][j]存储的是i的第j个因子,num[i]存i的质因子个数
void getphi()//求欧拉函数
{
    memset(num,0,sizeof(num));
    for(int i=1;i<M;i++)
        phi[i]=i;
    for(int i=2;i<M;i++)
        if(phi[i]==i)
        {
            phi[i]=i-1;//质数的欧拉函数是它本身-1
            for(int j=i<<1;j<M;j+=i)//求欧拉函数和质因子数
                phi[j]=phi[j]-phi[j]/i,prime[j][num[j]++]=i;
        }
    for(int i=2;i<M;i++)
        phi[i]+=phi[i-1];
}
int dfs(int a,int b,int n)
{
    if(!b)return 0;
    int count=0;
    for(int i=a;i<num[n];i++)
        count+=b/prime[n][i]-dfs(i+1,b/prime[n][i],n);
    return count;//返回在1~b之间与n不互质的个数
}
int main()
{
    getphi();
    int t,cas=1;
    scanf("%d",&t);
    while(t--)
    {
        int a,b,c,d,k,flag;
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
        printf("Case %d: ",cas++);
        if(!k){printf("0\n");continue;}//如果k=0,则输出0
        b/=k;
        d/=k;
        if(b>d){flag=b;b=d;d=flag;}
        long long ans=phi[b];//求1~b中的gcd为1的个数
        for(int i=b+1;i<=d;i++)//求b+1~d中与1~b中gcd为1的个数
            ans+=b-dfs(0,b,i);//容斥原理
        printf("%I64d\n",ans);//杭电不认%lld,坑~~
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值