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
", 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
",i, ans1 - (ans2 >> 1));
52     }
53     return 0;
54 }
View Code

因为对于某些连续的 i 会有 b / i, d / i 是相同的, 这种情况可以通过前缀和优化一下 .

优化代码:

 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 = 1e5 + 10;
 8 
 9 bool check[MAXN];
10 int prime[MAXN], mu[MAXN], sum[MAXN];
11 
12 void Moblus(void){
13     memset(check, false, sizeof(check));
14     int tot = 0;
15     mu[1] = 1;
16     sum[1] = 1;
17     for(int i = 2; i < MAXN; i++){
18         if(!check[i]){
19             prime[tot++] = i;
20             mu[i] = -1;
21         }
22         for(int j = 0; j < tot && prime[j] * i < MAXN; j++){
23             check[i * prime[j]] = true;
24             if(i % prime[j] == 0){
25                 mu[i * prime[j]] = 0;
26                 break;
27             }else mu[i * prime[j]] = -mu[i];
28         }
29         sum[i] = sum[i - 1] + mu[i];
30     }
31 }
32 
33 ll solve(int b, int d){
34     ll ans = 0;
35     for(int i = 1, la = 0; i <= b; i = la + 1){
36         la = min(b / (b / i), d / (d / i));
37         ans += (ll)(sum[la] - sum[i - 1]) * (b / i) * (d / i);
38     }
39     return ans;
40 }
41 
42 int main(void){
43     Moblus();
44     int t, a, b, c, d, k;
45     scanf("%d", &t);
46     for(int i = 1; i <= t; i++){
47         scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
48         if(k == 0){
49             printf("Case %d: 0
", i);
50             continue;
51         }
52         b /= k;
53         d /= k;
54         if(b > d) swap(b, d);
55         ll ans1 = solve(b, d);
56         ll ans2 = solve(b, b);
57          printf("Case %d: %lld
", i, ans1 - (ans2 >> 1));
58     }
59     return 0;
60 }
View Code

就本题而言时间从 31ms 优化到了 15 ms .

原文地址:https://www.cnblogs.com/geloutingyu/p/7247863.html