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;
}

你可能感兴趣的:(容斥原理)