P3327 [SDOI2015]约数个数和(推公式)

P3327 [SDOI2015]约数个数和(推公式)_第1张图片

链接https://www.luogu.com.cn/problem/P3327

题意:给定n、m,求 ∑ i = 1 n ∑ j = 1 m d ( i j ) \sum_{i=1}^n\sum_{j=1}^md(ij) i=1nj=1md(ij)

推导
1、有个结论: d ( i j ) = ∑ x ∣ i ∑ y ∣ j [ g c d ( x , y ) = 1 ] d(ij)=\sum_{x|i}\sum_{y|j}[gcd(x,y)=1] d(ij)=xiyj[gcd(x,y)=1]
∑ i = 1 n ∑ j = 1 m d ( i j ) = ∑ i = 1 n ∑ j = 1 m ∑ x ∣ i ∑ y ∣ j [ g c d ( x , y ) = 1 ] \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] i=1nj=1md(ij)=i=1nj=1mxiyj[gcd(x,y)=1]

2、枚举倍数
∑ x = 1 n ∑ y = 1 m ∑ x ∣ i n ∑ y ∣ j m [ g c d ( x , y ) = 1 ] \sum_{x=1}^n\sum_{y=1}^m\sum_{x|i}^n\sum_{y|j}^m[gcd(x,y)=1] x=1ny=1mxinyjm[gcd(x,y)=1]

3、化简并且利用莫比乌斯函数的性质换元
∑ x = 1 n ∑ y = 1 m ⌊ n x ⌋ ⌊ m x ⌋ ∑ d ∣ g c d ( x , y ) μ ( d ) \sum_{x=1}^n\sum_{y=1}^m {\lfloor \frac nx \rfloor} {\lfloor \frac mx\rfloor} \sum_{d|gcd(x,y)} \mu(d) x=1ny=1mxnxmdgcd(x,y)μ(d)

4、枚举d,并且设n ∑ x = 1 n ∑ y = 1 m ⌊ n x ⌋ ⌊ m x ⌋ ∑ d = 1 n μ ( d ) [ d ∣ x 且 d ∣ y ] \sum_{x=1}^n\sum_{y=1}^m {\lfloor \frac nx \rfloor} {\lfloor \frac mx\rfloor} \sum_{d=1}^n \mu(d)[d|x 且 d|y] x=1ny=1mxnxmd=1nμ(d)[dxdy]

5、仔细观察这个式子,其实是可以再继续化简的, [ d ∣ x ] 、 [ d ∣ y ] [d|x]、[d|y] [dx][dy]中枚举的是d倍数,因此可以化简为:
∑ d = 1 n μ ( d ) ∑ x = 1 n ⌊ n x ⌋ [ d ∣ x ] ∑ y = 1 m ⌊ m x ⌋ [ d ∣ y ] \sum_{d=1}^n \mu(d) \sum_{x=1}^{n} {\lfloor \frac nx \rfloor}[d|x] \sum_{y=1}^m{\lfloor \frac mx \rfloor}[d|y] d=1nμ(d)x=1nxn[dx]y=1mxm[dy]

∑ d = 1 n μ ( d ) ∑ i = 1 ⌊ n d ⌋ ⌊ n d i ⌋ ∑ j = 1 ⌊ m d ⌋ ⌊ m d j ⌋ \sum_{d=1}^n \mu(d) \sum_{i=1}^{\lfloor \frac nd \rfloor} {\lfloor \frac n{di} \rfloor} \sum_{j=1}^{\lfloor \frac md \rfloor}{\lfloor \frac m{dj} \rfloor} d=1nμ(d)i=1dndinj=1dmdjm

6、然后我们设 f ( x ) = ∑ i = 1 x ⌊ x i ⌋ f(x)=\sum_{i=1}^x {\lfloor \frac xi \rfloor} f(x)=i=1xix,原式就可以化简为
∑ d = 1 n μ ( d ) f ( n d ) f ( m d ) \sum_{d=1}^n \mu(d) f(\frac nd) f(\frac md) d=1nμ(d)f(dn)f(dm)

7、同时 f ( x ) f(x) f(x)恰好是[1,x]中每个数的约数的个数之和,因此可以线性筛处理d[i],然后作前缀和即可

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+5,maxm=1e5+5;
const int mod=1e9+7,inf=0x7f7f7f7f;

const int N=5e4;
int visit[N+10],prime[N+10],cnt;
int mu[N+10],f[N+10],d[N+10],num[N+10];

void init()
{
	mu[1]=1,cnt=0,d[1]=1;
	for(int i=2;i<=N;++i)
	{
		if(!visit[i])
			prime[++cnt]=i,num[i]=1,d[i]=2,mu[i]=-1;
		for(int j=1;j<=cnt&&i*prime[j]<=N;++j)
		{
			visit[i*prime[j]]=1;
			if(i%prime[j]==0)
			{
				d[i*prime[j]]=d[i]/(num[i]+1)*(num[i]+2);
				num[i*prime[j]]=num[i]+1;
				break;
			}
			mu[i*prime[j]]=-mu[i];
			num[i*prime[j]]=1;
			d[i*prime[j]]=d[i]*2;
		}
	}
	for(int i=1;i<=N;++i)
		mu[i]+=mu[i-1],f[i]=f[i-1]+d[i];
}

int t,n,m; 

int main()
{
	init();
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		if(n>m) 
			swap(n,m);		
		int l=1,r;
		ll ans=0;
		while(l<=n)
		{
			r=min(n/(n/l),m/(m/l));
			ans+=1ll*(mu[r]-mu[l-1])*f[n/l]*f[m/l];
			l=r+1;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

你可能感兴趣的:(数论,推式子)