首页 > 代码库 > hdu1695(莫比乌斯反演)

hdu1695(莫比乌斯反演)

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

 

题意: 对于 a, b, c, d, k . 有 x 属于 [a, b],  y 属于 [c, d], 求 gcd(x, y) = k 的 x, y 的对数 . 其中 a = b = 1 .

注意: (x, y), (y, x) 算一种情况 .

 

思路: 莫比乌斯反演

可以参考一下: http://blog.csdn.net/lixuepeng_001/article/details/50577932

公式: F(n) = sigma f(d) , 其中 (n | d) ==> f(n) = sigma u(d / n) * F(d) , 其中 (n | d) .

其中 u 为莫比乌斯函数, 定义为:

  若 d = 1, 则 u(d) = 1;

  若 d = p1p2...pk, 则 u(d) = (-1)^k , 其中 pi 为互异质数;

  其他 u(d) = 0;

 

对于 gcd(x, y) = k, 显然有 gcd(x / k, y / k) = 1 . 那么原题等价于求 gcd(x, y) = 1, 其中 x 属于 (1, b / k), y 属于 (1, d / k) .

然后定义 f(n) 表示满足条件的 gcd(x,y) = n 的 (x, y) 对数,

再定义 F(n) 表示满足 n | gcd(x,y) 的 (x, y) 对数, 即 gcd(x, y) % n = 0 的x, y对数 .

那么我们要求的就是 f(1) .

通过前面推理不难发现 F(x) = n / x * m / x, 其中 n = b / k, m = d / k;

那么 f(1) = sigma u(d / 1) * F(d), 其中 1 | d 且 d <= min(n, m);

即 f(1) = sigma u(d) * (n / d) * (m / d);

 

关于去重: f‘(1) = sigma u(d) * (n / d) * (n / d), 其中 n 为 m, n中的最小值, 则 sol = f(1) - f‘(1) / 2;

代码:

技术分享
 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #define ll long long
 5 using namespace std;
 6 
 7 const int MAXN = 1e6 + 10;
 8 
 9 bool check[MAXN];
10 int mu[MAXN], prime[MAXN];
11 
12 void Moblus(void){
13     memset(check, false, sizeof(check));
14     int tot = 0;
15     mu[1] = 1;
16     for(int i = 2; i < MAXN; i++){
17         if(!check[i]){
18             prime[tot++] = i;
19             mu[i] = -1;
20         }
21         for(int j = 0; j < tot && i * prime[j] < MAXN; j++){
22             check[i * prime[j]] = true;
23             if(i % prime[j] == 0){
24                 mu[i * prime[j]] = 0;
25                 break;
26             }else mu[i * prime[j]] = -mu[i];
27         }
28     }
29 }
30 
31 int main(void){
32     int t, a, b, c, d, k;
33     Moblus();
34     scanf("%d", &t);
35     for(int i = 1; i <= t; i++){
36         scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
37         if(k == 0){
38             printf("Case %d: 0\n", i);
39             continue;
40         }
41         if(b > d) swap(b, d);
42         b /= k;
43         d /= k;
44         ll ans1 = 0, ans2 = 0;
45         for(int j = 1; j <= b; j++){
46             ans1 += (ll)mu[j] * (b / j) * (d / j);
47         }
48         for(int j = 1; j <= b; j++){
49             ans2 += (ll)mu[j] * (b / j) * (b / j);
50         }
51         printf("Case %d: %lld\n",i, ans1 - (ans2 >> 1));
52     }
53     return 0;
54 }
View Code

 

hdu1695(莫比乌斯反演)