P2522 [HAOI2011] Problem b的:HAOI2011 Problem b问题如何解决?

摘要:P2522 [HAOI2011] Problem b 大意 [sum_{x=a}^b sum_{y=c}^d [gcd(x, y) = k] ]思路 利用 容斥原理,我们可以将区间 ([a, b]) 和 ([c, d])
P2522 [HAOI2011] Problem b 大意 \[\sum_{x=a}^b \sum_{y=c}^d [\gcd(x, y) = k] \] 思路 利用 容斥原理,我们可以将区间 \([a, b]\) 和 \([c, d]\) 的限制简化为从 \(1\) 开始的形式。令 \(f(n, m, k)\) 表示 \(1 \le x \le n, 1 \le y \le m\) 且 \(\gcd(x, y) = k\) 的个数,则原式等于: \[f(b, d, k) - f(a-1, d, k) - f(b, c-1, k) + f(a-1, c-1, k) \] 对于 \(f(n, m, k)\),满足 \(\gcd(x, y) = k\) 等价于 \(\gcd(\frac{x}{k}, \frac{y}{k}) = 1\)。 令 \(n' = \lfloor \frac{n}{k} \rfloor, m' = \lfloor \frac{m}{k} \rfloor\),我们要算的是: \[\sum_{i=1}^{n'} \sum_{j=1}^{m'} [\gcd(i, j) = 1] \] 利用莫比乌斯函数的性质 \(\sum_{d|\gcd(i,j)} \mu(d) = [\gcd(i, j) = 1]\),代入得: \[\sum_{i=1}^{n'} \sum_{j=1}^{m'} \sum_{d|\gcd(i, j)} \mu(d) \] 通过枚举 \(d\) 调整求和顺序: \[\sum_{d=1}^{\min(n', m')} \mu(d) \lfloor \frac{n'}{d} \rfloor \lfloor \frac{m'}{d} \rfloor \] 代码 #include<bits/stdc++.h> using namespace std; const int MAXN = 50005; int mu[MAXN], pr[MAXN]; bool vis[MAXN]; int sum[MAXN], tot = 0; void init(int n){ mu[1] = 1; for(int i = 2;i <= n;i ++){ if(!vis[i]){ pr[++ tot] = i; mu[i] = -1; } for(int j = 1;j <= tot && pr[j] * i <= n;j ++){ vis[pr[j] * i] = 1; if(i % pr[j] == 0){ mu[pr[j] * i] = 0; break; } mu[pr[j] * i] = -mu[i]; } } for(int i = 1;i <= n;i ++){ sum[i] = sum[i - 1] + mu[i]; } } long long count(int a, int b, int d){ a /= d, b /= d; if(a > b) swap(a, b); long long ans = 0; for(int l = 1, r;l <= a;l = r + 1){ r = min(a / (a / l), b / (b / l)); ans += (long long)(sum[r] - sum[l - 1]) * (a / l) * (b / l); } return ans; } int main(){ init(50000); int t; cin >> t; while(t --){ int a, b, c, d, k; cin >> a >> b >> c >> d >> k; long long res = count(b, d, k) - count(a - 1, d, k) - count(b, c - 1, k) + count(a - 1, c - 1, k); cout << res << '\n'; } return 0; }