莫比乌斯反演
莫比乌斯反演
符号普及
规定下符号先吧
前缀
了解前缀对后面的理解很重要,不然后面全是懵的。一定要熟悉了解。
简单的小推论
数论分块
这个不学清楚,后面绝对完了。 求解
对于朴素的算法我们直接暴力枚举,时间复杂度
在
答案是可以。
也就是说我们需要找到最大的
结论还挺简单的,直接记下来就好了
每次我们对区间
for(int head=1,rear=0;head<=n;head=rear+1){
rear=n/(n/head);ans+=(rear-head+1)*(n/head);
积性函数
好啦现在我们开始了解下积性函数吧 (本章均默认全为积性函数)
如果两个数互素,满足
- 常函数
1(n)=1 - 恒等函数
id(n)=n - 欧拉函数
\phi(n)=\sum\limits_{i=1}^n[\gcd(i,n)=1] (n 以内与n 互质的数) - 莫比乌斯函数
\mu(n) (等下介绍)
务必牢记定义
Dirichlet 卷积
是时候介绍一下迪利克雷卷积了
规定
仔细体会这个式子,并记住。
常见卷积式
这蛮重要的!!!
介绍题目中最常用的卷积式
简单的结论直接记下就好
用多了就懂了
莫比乌斯函数
好!现在介绍一下陌生的莫比乌斯函数。
我们规定
那么
由于莫比乌斯是积性函数,所以根据定义(积性)展示我们的线性筛(连上欧拉函数一起附上好了):
void init(){
mu[1]=1;
phi[1]=1;
int cnt=0;
for(int i=2;i<maxn;i++){
if(!vis[i]){
prime[cnt++]=i;
mu[i]=-1;
phi[i]=i-1;
}
for(int j=0;j<cnt&&i*prime[j]<maxn;j++){
vis[i*prime[j]]=1;
if(i%prime[j]){
mu[i*prime[j]]=-mu[i];
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
else {
mu[i*prime[j]]=0;
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
}
}
}
性质:
由
得
莫比乌斯反演
本章的重头戏
积性函数有如下性质:
如果
则
用数论变化的证明就免了吧。
我还是比较喜欢卷积证法
证毕。
做题时的简单公式推导
就推一些吧,其他的自行做题积累。
-
\sum\limits_{i=1}^n\sum\limits_{m=1}^mf(i)g(j)\Rightarrow\sum\limits_{i=1}^n f(i) \sum\limits_{j=1}^m g(j) -
[ \gcd(i,j)=1 ]\Rightarrow \epsilon(\gcd(i,j))\Rightarrow \sum\limits_{d|\gcd{(i,j)}}\! \! \mu(d) -
\sum\limits_{i=1}^n\sum\limits_{j=1}^m[d\mid i,d\mid j]\Rightarrow \sum\limits_{i=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\sum\limits_{j=1}^{\left\lfloor\frac{m}{d}\right\rfloor}1\Rightarrow\left\lfloor\frac{n}{d}\right\rfloor\left\lfloor\frac{m}{d}\right\rfloor -
[k\mid\gcd(i,j)]\Rightarrow [k\mid i,k\mid j] 应用
其实莫比乌斯函数的运算在复杂中,又含有众多的套路。
借几道题我们来学习一下
P2257 YY的GCD
还记得之前用欧拉函数解决的这道题吗P2568 GCD
这题是升级版
但再用欧拉函数并不是很好解决
所以我们来用莫比乌斯反演来简化下计算,感受如此高妙的过程
为了慢慢理解,写的比较啰嗦,
套路的进行运算 2, 3式子
把
利用 1 式
利用 4 式
设
写好看一点
使用线性筛预处理所有
配合上整除分块算
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e7;
bool vis[maxn];
int mu[maxn],sum[maxn],prime[maxn];
void init(){
int cnt=0;
mu[1]=1;
for(int i=2;i<=maxn;i++){
if(!vis[i]){
mu[i]=-1;
prime[++cnt]=i;
}
for(int j=1;j<=cnt&&prime[j]*i<=maxn;j++){
vis[i*prime[j]]=1;
if(i%prime[j])mu[prime[j]*i]=-mu[i];
else {
mu[prime[j]*i]=0;
break;
}
}
}
for(int i=1;i<=cnt;i++)
for(int j=1;j*prime[i]<=maxn;j++)
sum[j*prime[i]]+=mu[j];
for(int i=1;i<=maxn;i++)sum[i]+=sum[i-1];
}
int main(){
init();
int t;
scanf("%d",&t);
while(t--){
int n,m;
scanf("%d%d",&n,&m);
long long ans=0;
for(int head=1,rear=0;head<=min(n,m);head=rear+1){
rear=min(n/(n/head),m/(m/head));
ans+=(long long)(n/head)*(m/head)*(sum[rear]-sum[head-1]);
}
printf("%lld\n",ans);
}
return 0;
}
题表
可以多看看题解感受一下
- P3455 [POI2007]ZAP-Queries
- 2522 [HAOI2011]Problem b
更多试题在杜教筛讲解中给出
如果觉得好,欢迎继续学习积性函数筛法----杜教筛