[HAOI2011]Problem b

莫比烏斯反演 + 整除分塊。ide

關於整除分塊:spa

對於 i <= x <= n / (n / i) 的 x
code

有 n / x = n / iblog

證實略,記住就好(滑稽)get

1 for(int i = 1, j; i <= n; i = j + 1) {
2     j = n / (n / i);
3     // j = std::(m / (m / i), n / (n / i)); 
4     // 操做區間[i, j] 
5 }
代碼實現

接下來看題:要求[a,b] ~ [c,d]中 gcd == k 的個數。it

按照套路,設io

f(x) = sum[x == g],F(x) = sum[x | g]event

發現離解題還差的很遠....class

下一步:發現能夠用相似二維前綴和的方式來求解。cli

問題轉化爲求 n, m 中 gcd == k

而後就很熟悉了...

而後就T了.......

注意到F(x) = (n / x) * (m / x),能夠整除分塊。

有個結論就是:

而後就能夠作了。

我本人不能想到這個結論,因而提供另外一種思路:

gcd(i, j) == k => gcd(i / k, j / k) == 1

在這二者之間能夠創建一一對應的映射。

因而咱們把m, n都/k,就成了求f(1),這個時候就是裸的整除分塊了。

 1 #include <cstdio>
 2 #include <algorithm>
 3 const int N = 50010;
 4 
 5 int sum[N], miu[N], p[N], top, k;
 6 bool vis[N];
 7 
 8 inline int F(int x, int n, int m) {
 9     return (n / x) * (m / x);
10 }
11 
12 inline void getmiu(int n = 50005) {
13     miu[1] = 1;
14     for(int i = 2; i <= n; i++) {
15         if(!vis[i]) {
16             p[++top] = i;
17             miu[i] = -1;
18         }
19         for(int j = 1; j <= top && i * p[j] <= n; j++) {
20             vis[i * p[j]] = 1;
21             if(i % p[j] == 0) {
22                 break;
23             }
24             miu[i * p[j]] = -miu[i];
25         }
26     }
27     for(int i = 1; i <= n; i++) {
28         sum[i] = sum[i - 1] + miu[i];
29     }
30     return;
31 }
32 
33 inline int solve(int n, int m) {
34     n /= k;
35     m /= k;
36     int c = m > n ? n : m;
37     int ans = 0;
38     /*for(int i = 1; i <= c; i++) {
39         //ans += miu[i] * F(i, n, m);
40         ans += miu[i] * (n / i) * (m /i);
41     }*/
42     for(int i = 1, j; i <= c; i = j + 1) { // [i, j]
43         j = std::min(n / (n / i), m / (m / i));
44         ans += (n / i) * (m / i) * (sum[j] - sum[i - 1]);
45     }
46     return ans;
47 }
48 
49 int main() {
50     int n, a, b, c, d;
51     getmiu();
52     scanf("%d", &n);
53     while(n--) {
54         scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
55         int ans = solve(b, d) - solve(b, c - 1) - solve(a - 1, d) + solve(a - 1, c - 1);
56         printf("%d\n", ans);
57     }
58 
59     return 0;
60 }
AC代碼
相關文章
相關標籤/搜索