【莫比乌斯】 BZOJ 2301 Problem b
题意:对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数
思路:ans = cal(b, d) - cal(a - 1, d) - cal(b, c - 1) + cal(a - 1, c- 1),加上分块处理
代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; template <class T> inline bool rd(T &ret) { char c; int sgn; if(c = getchar() , c == EOF) return false; while(c != '-' && (c < '0' || c > '9')) c = getchar(); sgn = (c == '-') ? -1 : 1; ret = (c == '-') ? 0 : (c - '0'); while(c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0'); ret *= sgn; return true; } const int MAX_N = 50007; int pcnt, prime[MAX_N], mu[MAX_N]; bool vis[MAX_N]; void Mobius(int n) { pcnt = 0; vis[1] = mu[1] = 1; for(int i = 2;i <= n; i++) { if(!vis[i]) prime[pcnt++] = i, mu[i] = -1; for (int j = 0; j < pcnt && prime[j] * i <= n; ++j) { vis[prime[j] * i] = true; if (i % prime[j] == 0) { mu[i * prime[j]] = 0; break; } else mu[i * prime[j]] = -mu[i]; } } } int a, b, c, d, k; int s[MAX_N]; ll cal(int l, int r) { l /= k, r /= k; int n = min(l, r); ll ans = 0; for (int i = 1, j = 0; i <= n; i = j + 1) { j = min(l / (l / i), r / (r / i)); ans += ((ll)s[j] - s[i - 1]) * (l / i) * (r / i); } return ans; } int main() { Mobius(MAX_N - 2); for (int i = 1; i < MAX_N; ++i) s[i] = s[i - 1] + mu[i]; int T; rd(T); while (T-- > 0) { rd(a), rd(b), rd(c), rd(d), rd(k); ll ans = cal(b, d) - cal(a - 1, d) - cal(b, c - 1) + cal(a - 1, c- 1); printf("%lld\n", ans); } return 0; }