洛谷P3327 笔记

传送门

题意

\(d(x)\)\(x\) 的因数个数,然后给定 \(T\) 组询问,对于每一个询问给定 \(n\)\(m\) ,求 \(\sum_{i=1}^{n}\sum_{j=1}^{m}\)

\(1 \le T,n,m \le 5 \times 10^4\)

正文

重要结论

这题的难点之一就是第一步的转换。

需要用到一个重要结论:\(d(ij)=\sum_{x|i}\sum_{y|j}[gcd(i,j)=1]\)

来自这位dalao的证明:

考虑从朴素的角度求出 \(d(x)\) ,一种可行的方法是枚举每种质因子的出现次数。

于是对于 \(s\) 的一种质因子 \(p\) ,设 \(cnt_{s,p}\) 表示 \(s\) 中有 \(cnt_{s,p}\)\(p\) ,则这种暴力的策略会枚举 \(p\)\(cnt_p\) 种不同的大小 \(p,p^2...p^{cnt_{s,p}}\) 。于是得出结论:对于 \(p\mid s\)\(p\) 会被枚举 \(cnt_p\) 次。

那么对于 \(s=ij\) ,只要让质因子被枚举 \(cnt_{i,p}+cnt_{j,p}\) 次即可。那么一种可行的策略就是枚举所有满足 \(x|i,y|j,gcd(x,y)=1\) 的数对,这样的话当 \(p\mid x\) 时,\(p\nmid y\) ,此时 \(p\) 被枚举 \(cnt_{x,p}\) 次。反之亦然。于是 \(p\) 共被枚举 \(cnt_{i,p}+cnt_{j,p}\) 次,满足条件。所以结论成立。

推柿子

于是原式变为 \(\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{x|i}\sum_{y|j}[gcd(i,j)=1]\)

这个 \([gcd(i,j)=1]\) 非常的臭,用莫比乌斯函数把它撅了。

于是转换成:\(\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{x|i}\sum_{y|j}\sum_{d|gcd(i,j)}\mu(d)\)

枚举 \(x,y\)。就有 \(\sum_{x=1}^{n}\sum_{y=1}^{m}\sum_{d|gcd(i,j)}\mu(d)\lfloor \frac{n}{x}\rfloor\lfloor\frac{m}{y}\rfloor\)

进一步地,枚举 \(d\)。于是 \(\sum_{d=1}^{min(n,m)}\mu(d)\sum_{x=1}^{\lfloor\frac{n}{d}\rfloor}\lfloor \frac{n}{dx}\rfloor\sum_{y=1}^{\lfloor\frac{m}{d}\rfloor}\lfloor\frac{m}{dy}\rfloor\)

这个时候思路已经逐渐出来了。后面的 \(\sum_{x=1}^{\lfloor\frac{n}{d}\rfloor}\lfloor \frac{n}{dx}\rfloor\)\(\sum_{y=1}^{\lfloor\frac{m}{d}\rfloor}\lfloor\frac{m}{dy}\rfloor\) 是标准的整除分块模板。设 \(g(i)=\sum_{i=1}^{n}\lfloor\frac{n}{i}\rfloor\) ,原式又变成了 \(\sum_{d=1}^{min(n,m)}\mu(d) g(\lfloor \frac{n}{d}\rfloor)g(\lfloor \frac{m}{d}\rfloor)\)

由于 \(\mu(d)\) 珂以线性筛预处理,于是就出现了整除分块套整除分块,非常鬼畜!但正解就是这样。

code

//writer:Oier_szc

#include <bits/stdc++.h>
#define TS cerr<<"I AK IOI"<<endl;
#define int long long
using namespace std;
const int N=5e4+5,INF=2e9,mod=1e9+7;
int t;
int n,m;
int primes[N],st[N],len=0;
int f[N],g[N];
void init()
{
	f[1]=1;
	for(int i=2;i<=5e4;++i)
	{
		if(!st[i]) primes[++len]=i,f[i]=-1;
		for(int j=1;j<=len&&primes[j]<=5e4/i;++j)
		{
			st[i*primes[j]]=true;
			if(i%primes[j]==0) 
			{
				f[i*primes[j]]=0;
				break;
			}
			else f[i*primes[j]]=-f[i];
		}
	}
	for(int i=1;i<=5e4;++i)
	{
		f[i]+=f[i-1];
		for(int l=1,r;l<=i;l=r+1)
		{
			r=i/(i/l);
			g[i]+=(r-l+1)*(i/l);
		}
	}
}
signed main()
{
	init();
	scanf("%lld",&t);
	while(t--)
	{
		scanf("%lld%lld",&n,&m);
		int R=min(n,m),ans=0;
		for(int l=1,r;l<=R;l=r+1)
		{
			r=min(n/(n/l),m/(m/l));
			ans+=(f[r]-f[l-1])*g[n/l]*g[m/l];
		}
		printf("%lld\n",ans);
	}
	return 0;
}
posted @ 2024-02-09 00:30  Oier_szc  阅读(28)  评论(0)    收藏  举报