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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1695

题意:x位于区间[a, b],y位于区间[c, d],求满足GCD(x, y) = k的(x, y)有多少组,不考虑顺序。

思路:a = c = 1简化了问题,原问题可以转化为在[1, b/k]和[1, d/k]这两个区间各取一个数,组成的数对是互质的数量,不考虑顺序。我们让d > b,我们枚举区间[1, d/k]的数i作为二元组的第二位,因为不考虑顺序我们考虑第一位的值时,只用考虑小于i的情况。对于i<=b,因为第一位[1, i]都可以取到,互质的对数就是欧拉函数值。现在考虑i位于[b/k+1, d/k],此时我们要用b - [1, b/k]中与i不互质数的个数,那么关键问题就是求[1, b/k]中与i不互质数的个数,我们将i分解质因子,在b/k范围内每个因子的倍数肯定与i不互质。设i的素因子分别的p1,p2...pk,则1..b/k中p1的倍数组成集合A1,p2的倍数组成集合A2,p3到A3.....pk到Ak, 由于集合中会出现重复的元素,所以用容斥原理来求A1并A2并A3.....并Ak的元素的数的个数。区间中与i不互质的个数 = (区间中i的每个质因数的倍数个数)-(区间中i的每两个质因数乘积的倍数)+(区间中i的每3个质因数的乘积的倍数个数)-(区间中i的每4个质因数的乘积)+ ...

code:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 typedef long long LL;
 6 const int MAXN = 100005;
 7 
 8 LL phi[MAXN];       // 欧拉函数的和
 9 int num[MAXN];      // 素因子个数
10 int p[MAXN][20];    // 素因子
11 
12 void init()
13 {
14     memset(phi, 0, sizeof(phi));
15     memset(num, 0, sizeof(num));
16     phi[1] = 1L;
17     for (int i = 2; i < MAXN; ++i) {
18         if (!phi[i]) {
19             for (int j = i; j < MAXN; j += i) {
20                 if (!phi[j]) phi[j] = j;
21                 phi[j] = phi[j] * (i - 1) / i;
22                 p[j][num[j]++] = i;
23             }
24         }
25         phi[i] += phi[i - 1];
26     }
27 }
28 
29 LL dfs(int idx, int b, int now) // 求不大于b的数中,与now不互质的数的个数;
30 {
31     LL ret = 0;
32     for (int i = idx; i < num[now]; ++i) { // 容斥原理来求A1并A2并A3.....并Ak的元素的数的个数
33         ret += b / p[now][i] - dfs(i + 1, b / p[now][i], now);
34     }
35     return ret;
36 }
37 
38 
39 int main()
40 {
41     init();
42     int nCase;
43     scanf("%d", &nCase);
44     for (int cas = 1; cas <= nCase; ++cas) {
45         int a, b, c, d, k;
46         scanf("%d %d %d %d %d", &a, &b, &c, &d, &k);
47         if (k == 0) {
48             printf("Case %d: 0\n", cas);
49             continue;
50         }
51         if (b > d) swap(b, d);
52         b /= k;
53         d /= k;
54         LL ans  = phi[b];
55         for (int i = b + 1; i <= d; ++i) {
56             ans += b - dfs(0, b, i); // 求不大于b的数中,与i不互质的数的个数
57         }
58         printf("Case %d: %lld\n", cas, ans);
59     }
60     return 0;
61 }

 

posted @ 2015-09-04 10:51  jasaiq  阅读(249)  评论(0编辑  收藏  举报