洛谷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;
}

浙公网安备 33010602011771号