GCD HDU - 1695

                                                              GCD

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


题意:给出5个整数:a,b,c,d,k,在区间[a,b]内选取一个数 x, 在[c,d]内选取一个数 y,使得GCD(x,y)=k。其中GCD(x,y)表示x和y的最大公约数。求这样的整数共有多少对。注意(x=5,y=7和x=7 y=5)是一样的。

     本题中的数据a=c=1;

分析:

(1) 由于gcd(x,y)=k,满足 gcd(x/k,y/k)=1,所以区间可以缩小为 [1/k,b/k],[1/k,d/k], 问题也就转化为取两区间中的元素 x, y,使得 gcd(x,y)=1;

(2) 由于gcd(x,y)=1与gcd(y,x)=1是相同的,假设x<y,于是可以先取小区间进行讨论, 由于 gcd(x,y)=1,利用欧拉函数,所以小区间可以计算为

             ans+=phi[1]+phi[2]+phi[3]+.............+phi[b](用欧拉函数的递推形式保存起来即可);

(3)对于[b/k+1 , d/k ],进行讨论,设y为这个区间里的一个元素,可以对y进行素因子分解,于是得到集合 :  {p1,p2,p3........},先求gcd(x,y)!=1的组合,用容斥原理讨论能被整除的个数,最后相减就能得到ans了。

AC代码如下:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
const int maxn=1e5+5;
int nsu[1000];///每个数的素因子
int no;    ///每个数的素因子的数量
int b,d,sum;

void dfs(int i,int nu,int x,int mu)///i表示要乘以prime数组的下标。
{                                  ///nu表示已经相乘的素因子的数量
    if(nu==x)                      ///x表示上限,最多有x个素因子相乘
    {                              ///已经相乘的素因子的值
        sum+=b/mu;
        return ;
    }
    if(i==no)
        return ;
    dfs(i+1,nu+1,x,mu*nsu[i]);
    dfs(i+1,nu,x,mu);
    return ;
}
int rong()
{
    int s=0;
    for(int i=1;i<=no;i++)
    {
        sum=0;
        dfs(0,0,i,1);
        if(i&1)///容斥原理,奇加偶减
            s+=sum;
        else
            s-=sum;
    }
    return b-s;
}
int main()
{
    int phi[maxn];
    int prime[maxn];///存储到maxn的所有素数
    int nprime=0;
    bool isprime[maxn];

    ///欧拉函数的递推形式
    for(int i=1;i<maxn;i++) phi[i]=i;
    for(int i=2;i<maxn;i+=2) phi[i]/=2;
    for(int i=3;i<maxn;i+=2)
        if(phi[i]==i)
    {
        for(int j=i;j<maxn;j+=i)
            phi[j]=phi[j]/i*(i-1);
    }

    ///线性筛素数
    memset(isprime,true,sizeof(isprime));
    isprime[0]=isprime[1]=false;
    for(long long i=2;i<=maxn;i++)
    {
        if(isprime[i])
        {
            prime[nprime++]=i;
            for(long long j=i*i;j<maxn;j+=i)
                isprime[j]=false;
        }
    }

    int t;
    int a,k,ca=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d%d%d",&a,&b,&a,&d,&k);
        if(k==0)
        {
            printf("Case %d: 0\n",++ca);
            continue;
        }
        b/=k;d/=k;
        if(b>d)
        {
           int temp=b;b=d;d=temp;
        }

        long long ans=0;
        for(int i=1;i<=b;i++)
            ans+=phi[i];
        for(int i=b+1;i<=d;i++)
        {
            no=0;   ///no为a的素因子的个数
            a=i;
            for(int j=0;j<nprime&&prime[j]*prime[j]<=a;j++)///对大于b小于等于d的数进行素因子的分解
                if(a%prime[j]==0)
                {
                  nsu[no++]=prime[j];
                  while(a%prime[j]==0)
                        a/=prime[j];
                }
                if(a>1)
                    nsu[no++]=a;
                ans+=rong();
        }
        printf("Case %d: %I64d\n",++ca,ans);
    }
    return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值