P3327 [SDOI2015]约数个数和

洛谷题目链接

挺简单的数论题

主要要知道一个式子:$$d(i imes j)=sumlimits_{x|i} sumlimits_{y|j} [gcd(x,y)=1]$$

具体证明其实挺简单的,这里给出一个大佬的博客

那么我们需要求的式子就是:$$sumlimits_{i=1}^N sumlimits_{j=1}^M sumlimits_{x|i} sumlimits_{y|j} [gcd(x,y)=1]$$

分组一下:$$sumlimits_{i=1}^N [x|i] sumlimits_{j=1}^M [y|j] [gcd(x,y)=1]$$

按照套路改为枚举(x,y):$$sumlimits_{x=1}^N leftlfloor frac{N}{x} ight floor sumlimits_{y=1}^M leftlfloor frac{M}{y} ight floor [gcd(x,y)=1]$$

套路的反演也行,不过这里用的是莫比乌斯函数的性质:$$sumlimits_{x=1}^N leftlfloor frac{N}{x} ight floor sumlimits_{y=1}^M leftlfloor frac{M}{y} ight floor sumlimits_{d|gcd(x,y)} mu (d)$$

改为枚举(d)并提前:$$sumlimits_{d=1}^N sumlimits_{x=1}^N sumlimits_{y=1}^M [d|gcd(x,y)] mu (d) leftlfloor frac{N}{x} ight floor leftlfloor frac{M}{y} ight floor$$

[sumlimits_{d=1}^N sumlimits_{x=1}^{leftlfloor frac{N}{d} ight floor} sumlimits_{y=1}^{leftlfloor frac{M}{d} ight floor} mu (d) leftlfloor frac{N}{dx} ight floor leftlfloor frac{M}{dy} ight floor ]

分组:$$sumlimits_{d=1}^N mu (d) sumlimits_{x=1}^{leftlfloor frac{N}{d} ight floor} leftlfloor frac{N}{dx} ight floor sumlimits_{y=1}^{leftlfloor frac{M}{d} ight floor} leftlfloor frac{M}{dy} ight floor$$

我们只要求出(sumlimits_{i=1}^n leftlfloor frac{n}{i} ight floor)就行

接下来是美滋滋的代码时间~~~


#include<iostream>
#include<cstdio>
#include<cstring>
#define N 50007
#define int long long
using namespace std;
int T,n,m,cnt;
int mu[N],sum[N],num[N],prime[N];
bool isp[N];
void Get()
{
	mu[1]=1;
	for(int i=2;i<=N-7;++i)
	{
		if(!isp[i])
		{
			prime[++cnt]=i;
			mu[i]=-1;
		}
		for(int j=1;j<=cnt&&(i*prime[j])<=N-7;++j)
		{
			isp[i*prime[j]]=1;
			if(i%prime[j]==0)
				break;
			else
				mu[i*prime[j]]=-mu[i];
		}
	}
	for(int i=1;i<=N-7;++i)
		sum[i]=sum[i-1]+mu[i];
	for(int i=1;i<=N-7;++i)
	{
		int res=0;
		for(int l=1,r;l<=i;l=r+1)
		{
			r=i/(i/l);
			res+=(r-l+1)*(i/l);
		}
		num[i]=res;
	}
}
signed main()
{
	Get();
	scanf("%lld",&T);
	while(T--)
	{
		scanf("%lld%lld",&n,&m);
		int ans=0;
		if(n>m)
			swap(n,m);
		for(int l=1,r;l<=n;l=r+1)
		{
			r=min(n/(n/l),m/(m/l));
			ans+=(sum[r]-sum[l-1])*num[n/l]*num[m/l];
		}
		printf("%lld
",ans);
	}
	return 0;
}

原文地址:https://www.cnblogs.com/yexinqwq/p/11110078.html