[HAOI 2011] Problem b
[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=2301
[算法]
首先,满足a <= x <= b , c <= y <= d , GCD(x,y) = k的二元组对数可以转化为求 :
1 <= x <= b , 1 <= y <= d , GCD(x,y) = k的二元组对数
- 1 <= x <= (a - 1) , 1 <= y <= d , GCD(x,y) = k的二元组对数
- 1 <= x <= b , 1 <= y <= (c - 1) , GCD(x,y) = k的二元组对数
+ 1 <= x <= (a - 1) , 1 <= y <= (c - 1) , GCD(x,y) = k的二元组对数
可以通过莫比乌斯函数 + 容斥原理解决 , 并用数论分块加速
时间复杂度 : O(T ( sqrt(A) + sqrt(B) ) ( 其中,sqrt表示开根号)
[代码]
#include<bits/stdc++.h> using namespace std; #define MAXN 50010 int T,a,b,c,d,k; int miu[MAXN],sum[MAXN]; inline void sieve() { static bool visited[MAXN]; for (int i = 1; i < MAXN; i++) { visited[i] = false; miu[i] = 1; } for (int i = 2; i < MAXN; i++) { if (visited[i]) continue; miu[i] = -1; for (int j = 2 * i; j < MAXN; j += i) { visited[j] = true; if ((j / i) % i == 0) miu[j] = 0; else miu[j] *= -1; } } for (int i = 1; i < MAXN; i++) sum[i] = sum[i - 1] + miu[i]; } inline int getsum(int l,int r) { return sum[r] - sum[l - 1]; } inline int solve(int x,int y) { int gi; int ret = 0; for (int i = 1; i <= min(x,y); i = gi + 1) { gi = min((x / (x / i)),(y / (y / i))); ret += (x / i) * (y / i) * getsum(i,gi); } return ret; } int main() { sieve(); scanf("%d",&T); while (T--) { scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); printf("%d\n",solve(b / k,d / k) - solve((a - 1) / k,d / k) - solve(b / k,(c - 1) / k) + solve((a - 1) / k,(c - 1) / k)); } return 0; }