1. 程式人生 > >[POI 2007] Zap

[POI 2007] Zap

answer oid void 轉化 其中 efi sum span 莫比烏斯

[題目鏈接]

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為莫比烏斯函數)

[代碼]

#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; }

[POI 2007] Zap