BZOJ 1101: [POI2007]Zap [莫比乌斯反演]
题意:求\(\sum\limits_{i=1}^n \sum\limits_{j=1}^m [gcd(i,j)=k]\),多组询问
简单套路一下
\[\sum_{d=1}^n \mu(d) \frac{n}{kd} \frac{m}{kd}
\]
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=5e4+5;
inline int read(){
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
return x*f;
}
int n, m, k;
int notp[N], p[N], mu[N];
void sieve(int n) {
mu[1] = 1;
for(int i=2; i<=n; i++) {
if(!notp[i]) p[++p[0]] = i, mu[i] = -1;
for(int j=1; j<=p[0] && i*p[j]<=n; j++) {
notp[i*p[j]] = 1;
if(i%p[j] == 0) {mu[i*p[j]] = 0; break;}
mu[i*p[j]] = -mu[i];
}
}
for(int i=1; i<=n; i++) mu[i] += mu[i-1];
}
ll cal(int n, int m, int k) {
n /= k; m /= k;
if(n > m) swap(n, m);
ll ans=0; int r;
for(int i=1; i<=n; i=r+1) {
r = min(n/(n/i), m/(m/i));
ans += (ll)(mu[r] - mu[i-1]) * (n/i) * (m/i);
}
return ans;
}
int main() {
//freopen("in","r",stdin);
sieve(N-1);
int T=read();
while(T--) {
n=read(); m=read(); k=read();
printf("%lld\n", cal(n, m, k));
}
}
Copyright:http://www.cnblogs.com/candy99/