[SDOI2015]约数个数和

题意:设d(i)为i的约数的个数,给你N,M,求

\sum_{i=1}^{N}\sum_{j=1}^{M}d(ij)

解析:

引理:

d(ij)=\sum_{x|i} \sum_{y|j}[gcd(x,y)==1]

证明:

1.若i,j互质,则该引理显然

2.若i,j不互质,我们考虑使用数学归纳法

若已有上述式子成立,我们再加入一个质数p

\\ i'=i*p^{a}\\ j'=j*p^{b}

d(i'j')=d(ij)*(a+b+1)

则我们考虑一下

\sum_{x|i'} \sum_{y|j'}[gcd(x,y)==1]

1.若x,y都不含p因子,则有d(ij)的贡献

2.若只有x含有p因子,则产生a*d(ij)的贡献

3.若只有y含有p因子,则产生b*d(ij)的贡献

综上可得:

d(i'j')=\sum_{x|i'} \sum_{y|j'}[gcd(x,y)==1]

故引理得证

引理2:

[gcd(i,j)==1]=\sum_{k|gcd(i,j)}\mu (k)

回到题目中的式子:

\sum_{i=1}^{N}\sum_{j=1}^{M}d(ij)=\sum_{i=1}^{N}\sum_{j=1}^{M}\sum_{x|i}\sum_{y|j}[gcd(x,y)==1]=\sum_{i=1}^{N}\sum_{j=1}^{M}[gcd(i,j)==1]*\left \lfloor \frac{N}{i}\right \rfloor*\left \lfloor \frac{M}{j} \right \rfloor

我们设

f(n)=\sum_{i=1}^{n}\left \lfloor \frac{n}{i} \right \rfloor

这个直接分块就行了

则上式就

=\sum_{k=1}^{min(N,M)}\mu (k)*f(\left \lfloor \frac{N}{k} \right \rfloor)*f(\left \lfloor \frac{M}{k} \right \rfloor)

这个直接分块算一下就行了

#include
#define ll long long
using namespace std;
const int MAX=5e4;
ll mu[MAX+10],sum[MAX+10];
int prime[MAX+10];
bool p[MAX+10];
int T,n,m,k,len;
void init(){
	mu[1]=1;
    for (int i=2;i<=MAX;i++) {
    	if (!p[i]) {
    		prime[++len]=i; mu[i]=-1;
    	}
    	for (int j=1;j<=len&&prime[j]*i<=MAX;j++) {
    		p[prime[j]*i]=1;
    		if (i%prime[j]==0) {
    			mu[prime[j]*i]=0; break;
    		} mu[prime[j]*i]=-mu[i];
    	}
    }
    for (int i=1;i<=MAX;i++) mu[i]+=mu[i-1];
    for (int i=1;i<=MAX;i++) {
    	for (int j=1;j<=i;j=k+1){
    		k=i/(i/j);
    		sum[i]+=(k-j+1)*(i/j);
    	}
    }	
}
ll solve(int n,int m)
{
	ll ans=0;
	for (int i=1;i<=min(n,m);i=k+1)
	{
		k=min(n/(n/i),m/(m/i));
		ans+=sum[n/i]*sum[m/i]*(mu[k]-mu[i-1]);
	}
	return ans;
}
int main()
{
	scanf("%d",&T);
	init();
	while (T--){
		scanf("%d%d",&n,&m);
		cout << solve(n,m) << endl;
	}
}

 

你可能感兴趣的:(莫比乌斯反演)