[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=1101
[算法]
首先 , 问题可以转化为求GCD(x,y) = 1,x <= a / d , y <= b / d,的二元组个数
令F(a,b,d)表示x <= a , y <= b , d | GCD(x,y)的二元组个数 , 显然 , 只需保证x和y都为d的倍数即可 , 因此 , F(a,b,d) = [a / d][b / d](其中,"[]"表示向下取整)
那么 , 要求互质的二元组个数 , 可以通过容斥原理进行计算 :
在没有限制的情况下 , 共有a * b对二元组 , 需要将答案减去公约数是2 , 3 , 5 , 7等素数的倍数的二元组 , 但这样会多减了如公约数为2且3的倍数的二元组 , 需要加上它。
不难发现 , Answer = sigma( miu(i) * F(a,b,i) )(1 <= i <= min(a,b) , miu为莫比乌斯函数)
可以通过数论分块快速计算 , 时间复杂度 : O(T * (sqrt(A) + sqrt(B)) ( 其中,sqrt表示开根号)
#include<bits/stdc++.h> using namespace std; #define MAXN 50010 int T,a,b,d; 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() { scanf("%d",&T); sieve(); while (T--) { scanf("%d%d%d",&a,&b,&d); printf("%d\n",solve(a / d,b / d)); } return 0; }