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

传送门

GCD
Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 8784    Accepted Submission(s): 3260



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

题目大意:
输入5个数,a, b, c, d, k, 其中 a = c = 1,所以 这题就是求[1,b],[1,d]最大公约数GCD为 k 的对数。而且没有顺序。

解题思路:
假设 GCD(x, y) == k,那么,x/k 与 y/k是肯定互素的,所以我们要求的就是[1,b/k],[1,d/k]之间互素的数的个数,所以我们很容易就想到的是欧拉函数,可以把b设置为小的那个数, 那么以y>x来保持唯一性
接下来分两种情况:
1. y <= b , 那么互素对数就是 1~a的欧拉函数的累计和(容易想到)
2. y >= b , 考虑用容斥原理,
3. 然后就随便搞一搞就行了。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
typedef long long LL;
const int MAXN = 1e5+5;
bool flag[MAXN];///标记数组
LL phi[MAXN];///欧拉函数值,i的欧拉函数值=phi[i]
LL p[MAXN];///素因子的值
LL cnt = 0;
void Get_phi()///筛法求欧拉函数
{
    cnt = 0;
    memset(flag, true, sizeof(flag));
    phi[1] = 1;
    for(int i=2; i<MAXN; i++)///线性筛法
    {
        if(flag[i])///素数
        {
            p[cnt++] = i;
            phi[i] = i-1;///素数的欧拉函数值是素数 - 1
        }
        for(int j=0; j<cnt; j++)
        {
            if(i*p[j] > MAXN)
                break;
            flag[i*p[j]] = false;///素数的倍数,所以i*p[j]不是素数
            if(i%p[j] == 0)///性质:i mod p == 0, 那么 phi(i * p) == p * phi(i)
            {
                phi[i*p[j]] = p[j] * phi[i];
                break;
            }
            else
                phi[i*p[j]] = (p[j]-1) * phi[i];///i mod p != 0, 那么 phi(i * p) == phi(i) * (p-1)
        }
    }
}
vector <LL> link[MAXN];

void Init()
{
    for(LL i=1; i<MAXN; i++)
    {
        LL k = i;
        for(LL j=0; p[j]*p[j]<=k; j++)
        {
            if(k%p[j] == 0)
            {
                link[i].push_back(p[j]);
                while(k%p[j]==0)
                    k /= p[j];
            }
            if(k == 1)
                break;
        }
        if(k > 1)
            link[i].push_back(k);
    }
}

void init()     //求每一个数的质因数,vector储存
{
    LL i, j, k;
    for(i = 1; i < MAXN; i++)
    {
        k = i;
        for(j = 0; p[j]*p[j] <= k; j++)
        {
            if(k%p[j] == 0)
            {
                link[i].push_back(p[j]);
                while(k%p[j] == 0)
                    k /= p[j];
            }
            if(k == 1) break;
        }
        if(k > 1) link[i].push_back(k);
    }
}
LL RongChi(LL a, LL b, LL num)
{
    LL ret = 0;
    for(LL i=a; i<link[num].size(); i++)
    {
        LL k = b/link[num][i];
        ret += k - RongChi(i+1, k, num);
    }
    return ret;
}

int main()
{
    Get_phi();
    Init();
    int T;
    LL a, b, c, d, k;
    cin>>T;
    for(int cas=1; cas<=T; cas++)
    {
        cin>>a>>b>>c>>d>>k;
        if(k == 0)
        {
            printf("Case %d: 0\n", cas);
            continue;
        }
        b/=k, d/=k;
        if(b > d)
            swap(b, d);
        LL ret = 0;
        for(int i=1; i<=b; i++)
            ret += phi[i];
        for(int i=b+1; i<=d; i++)
            ret += b - RongChi(0, b, i);
        printf("Case %d: %lld\n", cas,ret);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值