luogu P3455 [POI2007]ZAP-Queries
题目让我们求出
以下的n 是 题目中的 a, m 是 b
\[\sum_{i=1}^{n}\sum_{i = 1}^m [gcd(i,j) == d]\]
因为有\[gcd(i , j) == d\]
\[gcd(i / d , j / d) == 1\]
设\(f(k)=\sum_{i=1}^n\sum_{i=1}^m[gcd(i,j)==k]\)套用
\[\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)==d] = \sum_{i=1}^{\frac nd}\sum_{j=1}^{\frac md}gcd(i,j)==1\]
套用反演公式2
\[g(x) = \sum_{x|y}f(y)=\sum_{x|y}\sum_{i=1}^n\sum_{i=1}^mgcd(i,j)==y=\]
\[\sum_{i=1}^n\sum_{i=1}^m\sum_{x|gcd(i,j)}=\sum_{i=1}^n\sum_{i=1}^m\sum_{x|i,x|j}=[\frac nx][\frac mx]\]
我们求
\[f(1) = \sum_{1|y}\mu(\frac y1)g(y)=\sum_{y}^{min(n,m)}\mu(y)[\frac {\frac nd}{y}][\frac {\frac md}{y}]\]
可以用前缀和加分块使一次操作达到\(O(\sqrt n)\)
所以总复杂度:\(O(T \sqrt n)\)
#include <iostream>
#include <cstdio>
#define ll long long
const int maxN = 50000 + 7;
const int N = 50000;
int mu[maxN] , prime[maxN], num;
bool vis[maxN];
void init() {
mu[1] = 1;
for(int i = 2;i <= N;++ i) {
if( !vis[i] ) {
prime[++ num] = i;
mu[i] = -1;
}
for(int j = 1;j <= num && prime[j] * i <= N;++ j) {
vis[prime[j] * i] = true;
if(i % prime[j] == 0) break;
mu[i * prime[j]] = -mu[i];
}
}
for(int i = 1;i <= N;++ i) mu[i] += mu[i - 1];
return ;
}
inline void swap(int &a,int &b) {a ^= b ^= a ^= b;return;}
inline int min(int a,int b) {return a > b ? b : a ;}
int main() {
int T;
scanf("%d",&T);
init();
while(T --) {
int a,b,k;
scanf("%d%d%d",&a,&b,&k);
a /= k;b /= k;
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 += 1LL * ( mu[r] - mu[l - 1] ) * (a / l) * (b / l);
}
printf("%lld\n",ans);
}
}