## 【莫比乌斯反演】[BZOJ3994]约数个数和

i=1nj=1md(i×j)

Ans=i=1nj=1md(i×j)

d(i)=i=1nn/i=f(i)

Ans=i=1nj=1m[(i,j)==1]n/im/j

i=a×P
j=b×P

a×b×P2

a×b

d|nμ(d)=0(n>1)

Ans=i=1nj=1md|i,d|jμ(d)n/im/j

d|i,d|j

d=1min(n,m)μ(d)i=1n/dj=1m/dnidmjd

d=1min(n,m)μ(d)i=1n/dndij=1m/dmdj

i=1n/dndi=f(nd)

d=1min(n,m)μ(d)f(nd)f(md)

void Init(int up){
int tmp;
d[1] = 1, mu[1] = 1;
for(int i=2;i<=up;i++){
if(!nprime[i]){f[i] = 1; mu[i] = -1; prime[++pcnt] = i; d[i] = 2;}
for(int j=1;j<=pcnt&&(tmp = prime[j]*i)<=up;j++){
nprime[tmp] = true;
if(i % prime[j] == 0){
mu[tmp] = 0;
f[tmp] = f[i]+1;
d[tmp] = d[i]/(f[i]+1)*(f[i]+2);
break;
}
f[tmp] = 1;
d[tmp] = d[i] * 2;
mu[tmp] = -mu[i];
}
}
for(int i=2;i<=up;i++)
d[i] += d[i-1], mu[i] += mu[i-1];
}

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 50000;
int d[MAXN+10], f[MAXN+10], mu[MAXN+10], prime[MAXN/3], pcnt, ff, vv;
bool nprime[MAXN+10];
char ch;
int get()
{
ff=0,vv=0;
while(!isdigit(ch=getchar()))if(ch=='-')break;
if(ch=='-')ff=1;else vv=ch-48;
while(isdigit(ch=getchar()))vv=vv*10+ch-48;
if(ff==1)return -vv;else return vv;
}
void Init(int up){
int tmp;
d[1] = 1, mu[1] = 1;
for(int i=2;i<=up;i++){
if(!nprime[i]){f[i] = 1; mu[i] = -1; prime[++pcnt] = i; d[i] = 2;}
for(int j=1;j<=pcnt&&(tmp = prime[j]*i)<=up;j++){
nprime[tmp] = true;
if(i % prime[j] == 0){
mu[tmp] = 0;
f[tmp] = f[i]+1;
d[tmp] = d[i]/(f[i]+1)*(f[i]+2);
break;
}
f[tmp] = 1;
d[tmp] = d[i] * 2;
mu[tmp] = -mu[i];
}
}
for(int i=2;i<=up;i++)
d[i] += d[i-1], mu[i] += mu[i-1];
}
int main(){
long long Ans = 0;
Init(MAXN);
int n, m, T;
T = get();
while(T--){
Ans = 0;
n = get(); m = get();
if(n > m) swap(n, m);
for(int i=1,nex;i<=n;i=nex+1){
nex = min(n/(n/i), m/(m/i));
Ans += 1LL * (mu[nex] - mu[i-1]) * d[n/i] * d[m/i];
}
printf("%lld\n", Ans);
}

return 0;
}

posted on 2015-05-27 13:16  JeremyGuo  阅读(112)  评论(0编辑  收藏  举报