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 }