您的位置:首页 > 其它

BZOJ 1101: [POI2007]Zap [莫比乌斯反演]

2017-03-24 15:16 375 查看
题意:求\(\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
, p
, mu
;
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));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: