莫比乌斯反演:在刷题中成长
前言
本文讲述的 不是正宗的反演。
正宗的莫反要设两个函数,而本篇仅仅用到了莫比乌斯函数的性质。在征求同机房 dalao 的意见后,我暂且把这个东西叫做反演。
方便起见,设 \(a/b=\lfloor\frac{a}{b}\rfloor\)。
方便起见,以下的变量 \(n\) 全部 \(\le m\),且 \(n,m\) 为同一数量级。
本篇的内容循序渐进,建议读者从前往后读。
事实上,要暴切莫反题目,只需要掌握四样东西:
有些题目可能需要一些其它技巧,我们碰到了再说。
做数学最重要的就是多刷题、积累经验,尤其是莫反一类的题目,做多了你就会发现,都是套路。
所以,让我们从简单开始,一道一道地做下去吧。
1.
我们直接套上莫比乌斯函数的性质:
我们发现,\(d|gcd(i,j)\leftrightarrow d|i\land d|j\):
改变枚举对象,把 \(d\) 提到最前面(\(d\) 的取值范围是 \([1,\min(n,m)=n]\)(开头设了 \(n\le m\))):
把所有枚举到的 \(i\) 和 \(j\) 全部除掉 \(d\)(这种方法在下面会经常用):
后面的部分其实就是 \(\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor\) 个 \(\mu(d)\):
这个时候我们就可以停笔了。
我们只需要筛出 \(\mu\) 的前缀和,就可以使用整除分块 \(O(\sqrt{n})\) 的时间内计算出答案:
int s_mu[];//mu 的前缀和
long long calc(int n,int m){
if(n>m) swap(n,m);
long long res=0;
for(int i=1,j;i<=n;i=j+1){
j=min(n/(n/i),m/(m/i));
//此时对于 [i,j] 区间内的 d,n/d的值全部相同,m/d的值也全部相同
res+=1ll*(s_mu[j]-s_mu[i-1])*(n/i)*(m/i);
}
return res;
}
这道题一定要理解,下面几乎每道题都用到了这道题的结论,上面的所有推导过程我会直接一步带过。
P2158 [SDOI2008] 仪仗队(通过一点点转化便可以变成本题)
2.
这题其实就比上面那题多了一步。
众所周知:
所以:
还是把 \(i\) 和 \(j\) 全部除掉 \(k\):
问题转化为第一题。
三倍经验:
3.(重点)
我们 转换枚举对象为 \(\gcd(i,j)\)(这一步特别重要,基本上每道题都要用上一次):
看到 \(\sum_{i=1}^n \sum_{j=1}^m [\gcd(i,j)=d]\),我们通过第二题的一系列变换把柿子变成:
建议大家在这里停下来消化一下,因为接下来的信息量很大。
重点来了!
观察柿子的前面两个 \(\sum\):\(\sum_{d=1}^n \sum_{k=1}^{n/d}\)
不难看出,\(dk\) 的取值遍布 \([1,n]\)。
所以我们 更换求和指标,设 \(T=dk\),
看回原来的柿子,和式中还有两项 \(\mu(k)\) 和 \([d\in prime]\)。因为 \(d\) 和 \(k\) 取遍了 \(T\) 的因数,我们直接枚举:
合并起来,就变成了:
\(\left(\sum_{d|T} [d\in prime]\mu\left(\frac{T}{d}\right)\right)\) 可以在筛出 \(\mu\) 后 \(O(n\log \log n)\) 大力枚举每个数的质数因数直接预处理,算出前缀和后就可以配合前面的部分整除分块计算了。总复杂度 \(O(n\log\log n)+O(Q\sqrt{n})\)。
回顾一下,这道题用到了两个很重要的技巧:枚举 \(\gcd\) 和 更换求和指标,在下面的题目中都有应用。所以说这题不适合作为莫反的入门题。
再说一遍,这题非常重要,建议初学莫反的读者反复品味。
三倍经验:
SP4491 PGCD - Primes in GCD Table
4.
按照套路枚举 \(\gcd\):
常规操作:
按照套路更换指标:
后面的部分直接 \(O(n\ln n)\) 枚举因数预处理,或者,
由 \(id * \mu =\varphi\) 得 \(\sum_{d|n} d\times \mu\left(\frac{n}{d}\right)=\varphi(n)\),可以直接线性筛。
(不知道卷积的朋友们来看我的博客鸭)
然后就做完了。
五倍经验:
SP26017 GCDMAT - GCD OF MATRIX
如果读者卡常能力极强:
SP26045 GCDMAT2 - GCD OF MATRIX (hard)
小结
做到这里,大家应该能够初见莫反题的套路了。
在下面的题目中,这些套路大同小异:无非就是枚举 \(\gcd\)、更换求和指标,在加上和式化简的一些其他技巧,你会真正享受做题的过程。
接下来,我们推的柿子会更复杂,同时会融入更多好玩的技巧。
5.
直接搬出一个结论:
这个结论的证明不是我们的重点,我会放在这道题的最后。
我们把它代回原柿:
接下来这一步,我们把 \(x,y\) 都除掉了 \(d\),为了维持整个柿子的值不变,最后两项的分母要乘回来:
然后我们发现,\(\lfloor\frac{n}{dx}\rfloor\) 和 \(y\) 毫无关系,\(\lfloor\frac{m}{dy}\rfloor\) 和 \(x\) 毫无关系,所以把后面的部分分成两个和式的乘积:
设 \(S(n)=\sum_{x=1}^n \lfloor\frac{n}{x}\rfloor\),我们可以花 \(O(n\sqrt{n})\) 的时间暴力整除分块预处理出 \(S(n)\)。原式化为
整除分块计算即可,复杂度 \(O(n\sqrt{n})+O(Q\sqrt{n})\)。
这题主要用到了一些比较巧的和式变换。
这道题一开始结论的证明:
对于 \(nm\) 的每个因数 \(k\),我们用如下方法将其映射到 \((x,y)\),其中 \(x|n,y|m,\gcd(x,y)=1\):
-
\(x=1,y=1\)
-
对于 \(k\) 的每个不同的质因数 \(p\),设 \(p^a|n\land p^{a+1}\nmid n\),\(p^b|k\land p^{b+1}\nmid k\),则
这样,每个 \(k\) 都能映射到唯一的 \((x,y)\)。
对于满足 \(x|n,y|m,\gcd(x,y)=1\) 的 \((x,y)\),我们用如下方法将其映射到 \(k\),其中 \(k|nm\):
-
\(k=1\)
-
对于 \(nm\) 的每个不同的质因数 \(p\),\(\because \gcd(x,y)=1,\therefore [p|x\land p|y]=0\),
这样,每个 \((x,y)\) 都能映射到唯一的 \(k\)。
所以,\(nm\) 的因数 \(k\) 与满足 \(x|n,y|m,\gcd(x,y)=1\) 的 \((x,y)\) 一一对应。
所以,\(d(nm)=\sum_{x|n} \sum_{y|m} [\gcd(x,y)=1]\)。
6.
P1829 [国家集训队]Crash的数字表格 / JZPTAB
老套路:
这一步中,我们同样地把 \(i,j\) 全部除掉了 \(d\),所以 \(\frac{i\times j}{d}\) 要变成 \(d^2\times \frac{i\times j}{d}\) 即 \(i\times j\times d\)。
考虑求 \(S(n,m)=\sum_{i=1}^n \sum_{j=1}^m [\gcd(i,j)=1] i\times j\),求好之后可以直接整除分块。
线性筛出 \(\mu(n)\times n^2\) 的前缀和,后面两个是等差数列,整体可以 \(O(\sqrt{n})\) 算出。代入原式再来一次整除分块,复杂度 \(O(\sqrt{n})\times O(\sqrt{n})=O(n)\)。
23.5.11 upd.
\(O(n\ln n)-O(\sqrt n)\)。原方法做不了多组数据的原题。wssb。
7.
P6810 「MCOI-02」Convex Hull 凸包(评蓝的原因是有不用莫反的做法)
看到我们熟悉的 \(\sum_{d=1}^n \sum_{k=1}^{n/d}\),很自然地设 \(T=dk\):
众所周知,\(\mu * d = 1\),在本题中,\(τ=d\),所以 \(\sum_{k|T}\mu(k)τ\left(\frac{T}{k}\right)=1\)。
\(O(n)\) 筛出 \(τ\),\(O(n\ln n)\) 暴力计算即可。
8.
处理出每个数的出现次数 \(c_i\),设 \(n\) 为 \(\max\{a_i\}\),
下面这两步信息量比较大,但相信通过前面几道题的铺垫,理解它们对大家应该不成问题:
设 \(T=dk\):
这一步信息量其实也很大。。。还是解释一下吧
我们把和式里面的项一个一个地搬下来:
三个乘起来就是最终的柿子了。
我们 \(O(n\ln n)\) 暴力筛出 \(\sum_{k|T} k\times \mu(k)\),然后直接 \(O(n\ln n)\) 暴力枚举 \(T\),大力加上所有 \(i\times c_{iT}\),最终复杂度 \(O(n\ln n)\)。
思考题:
P3704 [SDOI2017]数字表格(这题评黑纯属虚高)
小结
通过上面四道好题的练习,大家对莫比乌斯函数性质的运用和对柿子的处理愈发熟练了。
接下来的题目要结合一些除了推柿子外的其它技巧,推柿子的难度和上面的四道题差不多,所以在推柿子的部分我将进一步减少文字说明,把重点放在和其它知识的结合上。
9.
我们维护每个数的出现次数 \(c_i\),设 \(n\) 为 \(\max\{a_i\}\),把问题转化成:
我们可以维护:
每当插入或删除一个数的时候,我们枚举这个数的因数 \(d\),直接修改 \(f_d\),再修改一下答案即可。
复杂度 \(O(k\times q)\),其中 \(k\) 是因数个数,\(k\approx 200\)。代码:
bool stat[];//a[i] 是否在我们维护的集合中
int a[],mu[],f[];
vector<int> d[];//因数
long long ans=0;int c1=0;
//当前答案;当前集合中 1 的个数
while(q--){
int x;scanf("%d",&x);
if(a[x]==1) c1+=stat[x]?-1:1;
if(stat[x]) for(int k:d[a[x]]) --f[k],ans+=mu[k]*(f[k]*f[k]-(f[k]+1)*(f[k]+1));
else for(int k:d[a[x]]) ++f[k],ans+=mu[k]*(f[k]*f[k]-(f[k]-1)*(f[k]-1));
stat[x]^=1;
printf("%lld\n",(ans-c1)>>1);
}
10.
我们维护:
这个会比上一题麻烦一点。
设 \(N=\max\{n\}=10^5\)。
我们把询问离线下来,按 \(a\) 从小到大排序,一个一个地处理,
对于每个询问,设前一个询问的 \(a\) 为 \(la\),
则对于每一个 \(la<\sigma(d)\le a\),我们枚举 \(d\) 在 \(N\) 以内的倍数 \(T\),把 \(f_T\) 加上自己的贡献。
我们线性筛出 \(\sigma\),然后把 \(N\) 以内的所有数按 \(\sigma\) 从小到大排序,就可以做到这一点。
由于是单点修改,整除分块需要求区间和,所以使用树状数组。
对于 \(1\le i\le N\),我们最多只会进行一次枚举倍数的操作,所以复杂度为 \(O(N\ln N)\),加上树状数组的复杂度就是 \(O(N\ln N\log N)\);
\(Q\) 次询问,每次整除分块,树状数组查询区间和,复杂度 \(O(Q\sqrt{N}\log N)\)。
代码:
namespace sf{
void upd(int x,int d);
int qry(int l,int r);
}//树状数组
struct node{
int num,sig;//数字,约数和
}nod[];
struct que{
int n,m,a,id;
}q[];
int sig[],mu[],p=1;//p:当前更新到的 d的指针
for(int k=1;k<=qn;++k){
if(q[k].a<=0) continue;
while(p<=N&&nod[p].sig<=q[k].a){
int i=nod[p].num;
for(int j=i;j<=N;j+=i) sf::upd(j,sig[i]*mu[j/i]);
++p;
}
int n=q[k].n,m=q[k].m,res=0;
if(n>m) n^=m^=n^=m;
for(int i=1,j;i<=n;i=j+1){
j=min(n/(n/i),m/(m/i));
res=(res+(sf::qry(i,j)%mod+mod)%mod*(n/i)%mod*(m/i))%mod;
}
ans[q[k].id]=res;
}
以上两道题需要动态维护。
11.
方便起见,设题目给的 \(k\) 为 \(c\)。
设 \(f(T)=\sum_{d|T} d^c\mu(\frac{T}{d})\),\(id_c\) 和 \(\mu\) 的狄利克雷卷积,是积性函数,线筛就完了。
对于 \(p^a(p\in prime,a\ge 1)\),我们求出 \(f(p^a)\):
众所周知,对于 \(k\ge 2\),\(\mu(p^k)=0\),
结合一个 \(cnt\) 数组,\(cnt_i\) 表示 \(i\) 的最小质因子的次数,
以及一个 \(num\) 数组,若 \(i\) 的最小质因子为 \(p\),则 \(num_i=p^{cnt_i}\),
线性筛就不难了,代码:
int F(int p,int a){
return (fpow(p,a*c)-fpow(p,(a-1)*c)+mod)%mod;
}
void sieve(){
f[1]=1;int nxt;
for(int i=2;i<=N;++i){
if(!vis[i]) pr[++pcnt]=i,cnt[i]=1,num[i]=i,f[i]=F(i,1);
for(int j=1;j<=pcnt&&(nxt=i*pr[j])<=N;++j){
vis[nxt]=1;
if(i%pr[j]==0){
cnt[nxt]=cnt[i]+1;
num[nxt]=num[i]*pr[j];
f[nxt]=1ll*f[nxt/num[nxt]]*F(pr[j],cnt[nxt])%mod;
//由 num[] 的定义,nxt/num[nxt] 和 pr[j] 是互质的
break;
}
cnt[nxt]=1;
num[nxt]=pr[j];
f[nxt]=1ll*f[i]*f[pr[j]]%mod;
}
}
for(int i=1;i<=N;++i) f[i]=(f[i-1]+f[i])%mod;
}
12.
不难发现 \(f(n)=\mu^2(n)\)。
我们设 \(S(n)=\sum_{i=1}^n \sum_{j=1}^n (i+j)^k\),重新定义 \(f(T)=\sum_{d|T} d\times \mu^2(d)\mu(\frac{T}{d})\),对这两个东西分别求解。
设
则 \(S(n)=G(2n)-2\times G(n)\),用数学归纳法证明。
当 \(n=1\) 时,显然;
假设 \(S(n)=G(2n)-2\times G(n)\),则
我们线性筛出 \(id_k\),跑一遍前缀和求 \(F\),再跑一遍前缀和求 \(G\),然后就可以 \(O(1)\) 求 \(S(n)\) 了。
2022.05upd:一个求 \(S(n)\) 的更快更简单的方法
考虑递推:
仍然线性筛出 \(id_k\) 并对其求前缀和即可递推求出所有 \(S_n\),比原方法20个点的总用时约少3s。
对于 \(p^a(p\in prime,a\ge 1)\),我们求 \(f(p^a)\)。
当 \(a=1\) 时,\(f(p)=1\times \mu(1)^2\times \mu(p)+p\times \mu(p)^2\times \mu(1)=p-1\);
当 \(a=2\) 时,\(f(p^2)=1\times \mu(1)^2\times \mu(p^2)+p\times \mu(p)^2\times \mu(p)+p^2\times \mu(p^2)^2\times \mu(1)=-p\);
当 \(a\ge 3\) 时,\(\forall d|p^a\),总有 \(p^2|d\) 或者 \(p^2|\frac{p^a}{d}\),
\(\therefore \mu(d)^2\mu(\frac{p^a}{d})=0\),\(\therefore f(p^a)=0\)。
然后我们就可以筛了。
int ff(int p,int k){
if(k==1) return p-1;
if(k==2) return -p;
return 0;
}
void sieve(){
f[1]=1;int nxt;
for(int i=2;i<=N;++i){
if(!vis[i]) pr[++pcnt]=i,cnt[i]=1,num[i]=i,f[i]=i-1;
for(int j=1;j<=pcnt&&(nxt=i*pr[j])<=N;++j){
vis[nxt]=1;
if(i%pr[j]==0){
cnt[nxt]=cnt[i]+1;
num[nxt]=num[i]*pr[j];
f[nxt]=1ll*f[nxt/num[nxt]]*ff(pr[j],cnt[nxt])%mod;
break;
}
cnt[nxt]=1;
num[nxt]=pr[j];
f[nxt]=1ll*f[i]*f[pr[j]]%mod;
}
}
}
以上两道题需要线性筛我们推出的积性函数。
13.
设 \(s(n)=\sum_{i=1}^n i\):
知道 \(f(n)=n^2\varphi(n)\) 的前缀和就可以整除分块了。
\(n\le 10^{10}\),很自然想到杜教筛。
根据我们对狄利克雷卷积的理解,我们构造出:
众所周知,\(\sum_{i=1}^n i^2=\frac{n(n+1)(2n+1)}{6}\)。
众所周知,\(\sum_{i=1}^n i^3=\left(\sum_{i=1}^n i\right)^2\)。
套上杜教筛的板子,我们就做完了。
总结
韩信带净化。。。莫反题的推柿子真的全是套路,难易的区分仅仅在于步骤的多少和柿子的复杂程度。
上面五题的额外技巧,也基本就是莫反能结合的全部了。
所以,大家在切完本篇的题目后,如果想继续切更难的题,基本不用铺垫额外的前置知识,做好面对更繁杂的柿子的准备就行了。
写在最后
连肝两天,还是把这篇博客写完了。
感谢读者读完这篇博客。本人水平有限,文中出现的所有题难度不超过紫;读者可以继续前行,去切作者同机房 dalao 的 题单 中的黑题——文中的所有题目均来自这个题单。
至于我,在目前,我的水平不足以支撑我做更高难度的题了。我会结束现在全身心投入到数学中的状态,转而将数学题作为日常训练中的一种调剂。偶尔,我应该会试着做几道比较简单的黑;以后,我也可能会另开一篇博客,专门讲莫反的黑题,但那是很久以后的事情了。
Goodbye,Maths!
Reference
莫比乌斯反演-让我们从基础开始 https://www.luogu.com.cn/blog/An-Amazing-Blog/mu-bi-wu-si-fan-yan-ji-ge-ji-miao-di-dong-xi
例题五-结论证明 https://siyuan.blog.luogu.org/solution-p3327
例题十二- \(S(n)\) 的推导过程 https://www.luogu.com.cn/blog/224236/solution-p6156