落谷 P3327 [SDOI2015]约数个数和 (莫比乌斯反演+分块)*

题目链接:https://www.luogu.org/problem/P3327题目描述

落谷 P3327 [SDOI2015]约数个数和 (莫比乌斯反演+分块)*_第1张图片
设d(x)为x的约数个数,给定N、M,求 ∑i=1N∑j=1Md(ij)\sumN_{i=1}\sumM_{j=1}d(ij)∑i=1N​∑j=1M​d(ij)
输入格式

输入文件包含多组测试数据。第一行,一个整数T,表示测试数据的组数。接下来的T行,每行两个整数N、M。
输出格式

T行,每行一个整数,表示你所求的答案。
输入输出样例
输入 #1

2
7 4
5 6

输出 #1

110
121

说明/提示

1<=N, M<=50000

1<=T<=50000


分析:

求 ∑ i = 1 N ∑ j = 1 M d ( i j ) 求\sum_{i=1}^N\sum_{j=1}^M{d(ij)} i=1Nj=1Md(ij)
对于d函数有个性质,在最上面题目链接页面中的解题报告中有它的证明,不过能力不够,不太理解,先记着吧
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]
注:[gcd(x,y)=1]表示gcd(x,y)等于1时值为1,其余情况为0
那么所求为
∑ i = 1 N ∑ j = 1 M ∑ x ∣ i ∑ y ∣ j [ g c d ( x , y ) = 1 ] \sum_{i=1}^N\sum_{j=1}^M{\sum_{x|i}\sum_{y|j}{[gcd(x,y)=1]}} i=1Nj=1Mxiyj[gcd(x,y)=1]
上式中,假如以x,y为自变量,i和j满足分别是x,y的倍数,对应的个数分别为 N x , M y \frac{N}{x},\frac{M}{y} xN,yM(注:像这种除法的,若没有特别说明,都表示向下取整),由此改变枚举顺序得
∑ x = 1 N ∑ y = 1 M [ g c d ( x , y ) = 1 ] ⋅ N x ⋅ M y \sum_{x=1}^N\sum_{y=1}^M{[gcd(x,y)=1]\cdot \frac{N}{x}\cdot \frac{M}{y} } x=1Ny=1M[gcd(x,y)=1]xNyM
定义f(n)函数,和g(n)函数:
f ( n ) : = ∑ x = 1 N ∑ y = 1 M [ g c d ( x , y ) = n ] ⋅ N x ⋅ M y g ( n ) : = ∑ n ∣ d f ( d ) = ∑ x = 1 N ∑ y = 1 M [ n ∣ g c d ( x , y ) ] ⋅ N x ⋅ M y f(n) :=\sum_{x=1}^N\sum_{y=1}^M{[gcd(x,y)=n]\cdot \frac{N}{x}\cdot \frac{M}{y} }\\ g(n):=\sum_{n|d}{f(d)}\\ =\sum_{x=1}^N\sum_{y=1}^M{[n|gcd(x,y)]\cdot \frac{N}{x}\cdot \frac{M}{y} } f(n):=x=1Ny=1M[gcd(x,y)=n]xNyMg(n):=ndf(d)=x=1Ny=1M[ngcd(x,y)]xNyM

题目所求为 f ( 1 ) f(1) f(1)
对g(n)进一步化简,由于 n ∣ g c d ( x , y ) n|gcd(x,y) ngcd(x,y),所以令 x = a ⋅ n , y = b ⋅ n x=a\cdot n,y=b\cdot n x=an,y=bn,代入得
g ( n ) = ∑ a ⋅ n = 1 N ∑ b ⋅ n = 1 M [ n ∣ g c d ( a ⋅ n , b ⋅ n ) ] ⋅ N a ⋅ n ⋅ M b ⋅ n = ∑ a = 1 N n ∑ b = 1 M n [ 1 ∣ g c d ( a , b ) ] ⋅ N a ⋅ n ⋅ M b ⋅ n = ∑ a = 1 N n ∑ b = 1 M n N a ⋅ n ⋅ M b ⋅ n g(n)=\sum_{a\cdot n=1}^N\sum_{b\cdot n=1}^M{[n|gcd(a\cdot n,b\cdot n)]\cdot \frac{N}{a\cdot n}\cdot \frac{M}{b\cdot n} }\\ =\sum_{a =1}^{\frac{N}{n}}\sum_{b=1}^{\frac{M}{n}}{[1|gcd(a,b)]\cdot \frac{N}{a\cdot n}\cdot \frac{M}{b\cdot n} }\\ =\sum_{a =1}^{\frac{N}{n}}\sum_{b=1}^{\frac{M}{n}}{\frac{N}{a\cdot n}\cdot \frac{M}{b\cdot n} } g(n)=an=1Nbn=1M[ngcd(an,bn)]anNbnM=a=1nNb=1nM[1gcd(a,b)]anNbnM=a=1nNb=1nManNbnM
反演得:
f ( n ) = ∑ n ∣ d μ ( d n ) g ( d ) f(n)=\sum_{n|d}{μ(\frac{d}{n})g(d)} f(n)=ndμ(nd)g(d)
n = 1 n=1 n=1代入得
f ( 1 ) = ∑ 1 ∣ d μ ( d ) g ( d ) = ∑ d = 1 m i n ( N , M ) μ ( d ) g ( d ) = ∑ d = 1 m i n ( N , M ) μ ( d ) g ( d ) f(1)=\sum_{1|d}{μ(d)g(d)}\\ =\sum_{d=1}^{min(N,M)}{μ(d)g(d)}\\ =\sum_{d=1}^{min(N,M)}{μ(d)g(d)} f(1)=1dμ(d)g(d)=d=1min(N,M)μ(d)g(d)=d=1min(N,M)μ(d)g(d)
定义s(n)函数
s ( n ) : = ∑ i = 1 n n i s(n):=\sum_{i=1}^{n}{\frac{n}{i}} s(n):=i=1nin
则有
g ( n ) = ∑ a = 1 N n ∑ b = 1 M n N a ⋅ n ⋅ M b ⋅ n = ∑ a = 1 N n N a ⋅ n ∑ b = 1 M n M b ⋅ n g(n)=\sum_{a =1}^{\frac{N}{n}}\sum_{b=1}^{\frac{M}{n}}{\frac{N}{a\cdot n}\cdot \frac{M}{b\cdot n} }\\ =\sum_{a =1}^{\frac{N}{n}}{{\frac{N}{a\cdot n}\sum_{b=1}^{\frac{M}{n}} \frac{M}{b\cdot n} }} g(n)=a=1nNb=1nManNbnM=a=1nNanNb=1nMbnM
由于a,b间没有关联,故

g ( n ) = s ( N n ) ⋅ s ( M n ) g(n)=s(\frac{N}{n})\cdot s(\frac{M}{n}) g(n)=s(nN)s(nM)
所以
f ( 1 ) = ∑ d = 1 m i n ( N , M ) μ ( d ) g ( d ) = ∑ d = 1 m i n ( N , M ) μ ( d ) ⋅ s ( N d ) ⋅ s ( M d ) f(1)=\sum_{d=1}^{min(N,M)}{μ(d)g(d)}=\sum_{d=1}^{min(N,M)}{μ(d)\cdot s(\frac{N}{d})\cdot s(\frac{M}{d})} f(1)=d=1min(N,M)μ(d)g(d)=d=1min(N,M)μ(d)s(dN)s(dM)
对于s函数,分块求,得预处理,否则会超时。对于μ,预处理求前缀和,求μ*s*s的时候也得分块求

代码:

#include 

using namespace std;
const int N=5e4+5;
#define ll long long 

int prime[N+1];
int mob[N+1];
ll sum[N+1];
ll s[N+1];

void Mobius()
{
	memset(prime,0,sizeof(prime));
	mob[1]=1;
	sum[1]=1;
	for(int i=2;i<=N;i++)
	{
		if(!prime[i])
		{
			prime[++prime[0]]=i;
			mob[i]=-1;
		}
		for(int j=1;j<=prime[0] && i*prime[j]<=N;j++)
		{
			prime[i*prime[j]]=1;
			if(i%prime[j]==0)
			{
				mob[i*prime[j]]=0;
				break;
			}
			mob[i*prime[j]]=-mob[i];
		}
		sum[i]=sum[i-1]+mob[i];
	}
}

void get_s()
{
	/* ll ans=0;
	for(int l=1, r;l<=n;l=r+1)
	{
		r=n/(n/l);
		ans += 1LL*(r-l+1)*(n/l);
	}
	return ans; */
	for(int x=1;x<=N;x++)
	{
		s[x]=0;
		for(int l=1,r; l<=x;l=r+1)
		{
			r=x/(x/l);
			s[x] += 1LL*(r-l+1)*(x/l);
		}
	}
	
}

ll solve(int n,int m)
{
	ll ans=0;
	int lim=min(n,m);
	for(int l=1,r ; l<=lim; l=r+1)
	{
		r=min( n/(n/l),m/(m/l) );
		ans += 1LL*(sum[r]-sum[l-1])*s[n/l]*s[m/l];
	}
	return ans;
}


int main()
{
	Mobius();
	get_s();
	int T, n, m;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		printf("%lld\n",solve(n,m));
		
	}
	return 0;
}

参考资料:

  • siyuan的博文
  • oi wiki 莫比乌斯反演

你可能感兴趣的:(落谷 P3327 [SDOI2015]约数个数和 (莫比乌斯反演+分块)*)