HDU1695(容斥)

GCD

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

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

题意:让你找出(1, b) 中找一个数x, (1, d)中找一个数y使得gcd(x, y) == k,让你输出所有满足条件的对数,但是(x1, x2) 与(x2, x1)算一对。

解题思路:gcd(x, y) == k,于是我们可以得到x / k 与 y / k互质,于是问题转化为在范围(1 , b \ k)与范围(1 , d\ k)中有多少对互质的数,当然我们的做法是枚举其中一个区间的每一个数,看另外一个区间有多少与之互质的数,但是我们求解一个数x与一个区间(1, m)中有多少与之互质的数,直接求好像除了暴力以外没有更好的方法,所以我们考虑一下正难则反的思想,求一下区间中与x不互质的数就行,我们根据数论知识可知,一个数可以唯一分解为素数的乘积,假设x 可以分解成x = p1* p2*p3….其中p1, p2,p3都是质数,所以一个数只要是p1的倍数或者p2的倍数,。。。。都与x不互质,而且在区间(1, m)中,是p1的倍数的数的个数不用暴力找,直接可以得到是m / p1,这样我们就可以找出所以的p1的倍数的个数,p2倍数的个数….然后这些集合肯定有重合,因为肯定有数既是p1,的倍数又是p2的倍数,比如6就是质数2, 3的倍数,所以这些集合肯定有交集,不能直接相减,所以我们需要用容斥求解一下这些集合的并就行。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
int a, b, c, d, k;
ll ans, res;
vector<int> g[maxn];//对2 - maxn之内的数进行素数分解
bool flag[maxn];
void init()
{
    memset(flag, false, sizeof(flag));
    for(int i = 0; i < maxn; i++)
    {
        g[i].clear();
    }
    for(int i = 2; i < maxn; i++)
    {
        if(!flag[i])
        {
            for(int j = i; j < maxn; j += i)
            {
                g[j].push_back(i);
                flag[j] = true;
            }
        }
    }
}
void dfs(int now, int loc, int cnt, int value, int x)
{
   if(loc >= g[now].size()) return;
   if(cnt&1) ans += (ll)value / x;
   else ans -= (ll)value / x;
   for(int i = loc + 1; i < g[now].size(); i++)
   {
       dfs(now, i, cnt + 1, value, x * g[now][i]);
   }
}
int main()
{
    int T;
    int Case = 1;
    scanf("%d", &T);
    init();
    while(T--)
    {
        scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
        if(k == 0)
        {
            printf("Case %d: 0\n", Case++);
            continue;
        }
        if(b > d) swap(b, d);
        res = 0;
        b /= k;
        d /= k;
        if(b)//1与任何数互质
        res += (ll)d;
        for(int i = 2; i <= b; i++)//枚举第一个数
        {
            res += (ll)(d - i);//先加上所有的可能情况
            ans = 0;
            for(int j = 0; j < g[i].size(); j++)
            {
                dfs(i, j, 1, d - i, g[i][j]);
            }
            res -= ans;//减去与i不互质的个数
        }
        printf("Case %d: %lld\n", Case++, res);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值