【学习笔记】莫比乌斯反演
前置知识:
积性函数:
对于互质整数\(a\) ,\(b\),如果有\(f(a\times b)=f(a) \times f(b)\) ,那么称\(f(x)\)为积性函数,例如 \(\varphi,\mu,\sigma,d\)
而完全积性函数是对于任意的整数\(a\) , \(b\),有\(f(a \times b)=f(a) \times f(b)\)的数论函数如 \(\epsilon,I ,id\)
Mobius 函数( μ ):
\(\mu(n) = \begin{cases} 1, & n = 1 \\ (-1)^m, &n = \prod_{i=1}^{n} \space p_i \\ 0, &otherwise \end{cases}\)
可以看出,$ μ(n) $ 恰在 \(n\) 无平方因子时取值非零。
可以线性筛
inline void prework(){
miu[1]=1;
for(int i=2;i<N;++i){
if(!vis[i]) pri[cnt++]=i,miu[i]=-1;
for(int j=0;j<cnt&&i*pri[j]<N;++j){}
vis[i*pri[j]]=1; if(i%pri[j]) miu[i*pri[j]]=-miu[i];
else{miu[i*pri[j]]=0; break;}
} miu[i]+=miu[i-1];
} return ;
}
Dirichlet 卷积
同时 \(\epsilon\) 函数是 \(Dirichlet\) 卷积的单位元,即 \(f = f \ast \epsilon\)
常见的卷积式子有: \(\mu * I=\epsilon,\varphi * I= id,\mu * id = \varphi\)
这些卷积的正确性证明都可以通过考察因数的计算次数得到
Mobius 反演
设 \(f\) 是数论函数,定义函数 \(g\) 满足
证明先直接带入并整理,再根据 \(I * \mu =\epsilon\) 即可得到除了 \(x=n\) 之外的 \(f(x)\) 在 \(f(n)\) 中的贡献次数为 \(0\) 而 \(f(n)\) 的贡献次数为 \(1\)
例题
推式子一般使用如下方式
1.枚举 \(gcd\),除掉 \(d\)
2.\([gcd(i,j)=1] \rightarrow \sum\limits _ {d|i,d|j} \mu(d)\)
3.\(T=dp\) 然后提出来 \(T\)
感觉还是理解反演本质非常重要,甚至很多题目都是使用最本源的莫比乌斯反演公式设两个函数就可以得到非常简洁的,可以求解的式子
约数个数和
通过下式将原式展开并使用 \(\le n\) 中 \(x\) 的倍数个数就能得到简洁表达
最终表达式是积性函数求和,需要搭配线性筛
一个人的数论
设自然数幂前缀和 \(S_d(n)=\sum\limits_{i=1}^n i^d\),那么则有
将自然数幂表示为多项式,设数列 \(\{a\}\) 为其系数:
然后看看后面的部分就是两个函数 \(u(x)=x^d \mu (x)\) 和 \(v(x)=x^i\) 的狄利克雷卷积,可以线性筛得到,对于这里而言就是把互质的函数值乘起来
\((u*v)_i(p^a)\) 把 \(\mu\) 的值为 \(0\) 的部分消掉之后剩下了:\(p^{ai}(1-p^{d-i})\)
Code Display
const int mod=1e9+7,N=1010;
inline int ksm(int x,int y){
if(y<0) return ksm(ksm(x,-y),mod-2);
int res=1; for(;y;y>>=1,(x*=x)%=mod) if(y&1) res=res*x%mod;
return res;
}
int ans,n,d,p[N][2],m[N][N],res[N],sum[N];
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
signed main(){
d=read(); n=read();
for(int i=1;i<=n;++i) p[i][0]=read(),p[i][1]=read();
for(int i=0;i<=d+2;++i){
int res=0; for(int j=1;j<=i+1;++j) res=add(res,ksm(j,d));
m[i][d+2]=res; m[i][0]=1;
for(int j=1;j<=d+1;++j) m[i][j]=m[i][j-1]*(i+1)%mod;
}
for(int i=0;i<=d+2;++i){
int t=i;
for(int j=i;j<=d+2;++j) if(m[j][i]){t=j; break;}
for(int j=i;j<=d+2;++j) swap(m[i][j],m[t][j]);
for(int j=i+1;j<=d+2;++j){
int x=m[j][i]*ksm(m[i][i],mod-2)%mod;
for(int k=i;k<=2+d;++k) m[j][k]=(m[j][k]-m[i][k]*x%mod+mod)%mod;
}
}
for(int i=d+2;i>=0;--i){
m[i][d+2]=m[i][d+2]*ksm(m[i][i],mod-2)%mod;
for(int j=i-1;j>=0;--j) m[j][d+2]-=m[i][d+2]*m[j][i]%mod,m[j][d+2]=(m[j][d+2]+mod)%mod;
}
for(int i=0;i<=d+1;++i) res[i]=m[i][d+2];
// Solve Equation
for(int i=0;i<=d+1;++i){
int tmp=1;
for(int j=1;j<=n;++j){
tmp=tmp*ksm(p[j][0],p[j][1]*i)%mod*((1-ksm(p[j][0],d-i)+mod)%mod)%mod;
}
ans=add(ans,res[i]*tmp%mod);
} cout<<ans<<endl;
return 0;
}
2021-03-29 数列
原题可以被分成快速求 \(A,B\) 数列和求行列式两部分
第一部分考虑将原题中的式子分成 \(n\) 对 \(4\) 的模数进行考虑
那么不难用 \(\log n\) 的时间将原题转化成一个 \(\frac{n}4\) 的子问题,复杂度 \(n\log^2n\) ,不能通过
考虑预处理序列的前 \(n\) 位那么复杂度变为 \(\Theta(n+k\log^2 \frac{max}n)\)
第二问考虑设 \(B_{F(x)}=\sum_{k|x} g(k),g(x)=\sum_{k|x} \mu (\frac{x}k) B_{F(k)}\)
所以矩阵会转化成 \(Mat_{i,j}=[i|j]g(i)\),证明考虑归纳,然后手动消下一行的元
这部分复杂度 \(\Theta(n\log n)\)