关于莫比乌斯反演
狄利克雷卷积与数论函数:
狄利克雷卷积写作:
定义:
也可以写作:
狄利克雷卷积满足交换律与结合律:
狄利克雷卷积是一个对称的结构
一些简单的数论函数:
定义:积性函数:
对于一个函数 \(F\) , 如果 \(gcd(a,b)=1\) 时有\(F(ab)=F(a)F(b)\),则该函数是积性函数。
定义:完全积性函数:
对于任意的整数 \(a\) 和 \(b\) 有 \(F(ab)=F(a)F(b)\)
很明显,完全积性函数∈积性函数。
一些常见的积性函数:
恒等函数,无论 \(n\) 是啥,它永远等于1:
元函数,当 \(n=1\) 时,函数值为 \(1\),否则为 \(0\):
单位函数:
幂函数,单位函数是它的特殊情况:
欧拉函数,小于n的整数中,与n互质的数的个数:
以及下文要用到的莫比乌斯函数 \(\mu(n)\)
积性函数的一些性质:
积性函数的逆也是积性函数:
首先,定义函数在狄利克雷卷积意义下的逆:
考虑:
即:
即:
那么,如果 \(G*F=e\) ,我们就说 \(F\) 与 \(G\) 互逆
下证:
因为:
考虑归纳证明:
当 \(a=1\) 或 \(b=1\) 时:
若 \(a,b\) 均等于 \(1\) ,\(e(1)=F(1)*F^{-1}(1)=1\)
而 \(F(1)=1\) ,因此 \(F^{-1}(1)=1\)
当 \(a,b>1\) 时:
设,对于 \(\forall a'<a,b'<b\),都有 \(F^{-1}(a'b')=F^{-1}(a')F^{-1}(b')\)
下证 \(F^{-1}(ab)=F^{-1}(a)F^{-1}(b)\)
显然,有:
即:
有:
证毕
莫比乌斯反演:
设:
显然:
即:
那么:
现在只需要求 \(I^{-1}\) 即可通过 \(F\) 反演出 \(f\) 。
令 \(\mu=I^{-1}\),显然 \(\mu\) 是积性函数。
先从 \(\mu(p^k)\) 入手:
当 \(k=0\) 时:
因此 \(\mu(1)=1\)
\(k=1\) 时:
\(k=2\) 时:
\(k>2\) 时,数学归纳法可证 \(\mu(p^k)=0\)
因此,若:
则:
这就有了莫反的第一种形式:
也是最常用的形式。
还有倍数形式:
可以左式代入右式中证明,更简单的方法是像二项式反演那样,直接把转移写成矩乘的形式,转置一下即可。
以上两个式子由于转移方向单一,而且复杂度没什么优化,所以一般可以直接一层容斥解决,不需要莫反
更有用的是嵌入式莫反:
因为:
所以:
由于:
所以:
莫比乌斯反演与整除分块:
- (1)求:
我们使用嵌入式反演,有:
由于:
因此:
预处理前缀和,整除分块即可在 \(O(\sqrt n)\) 时间内求解
- (2)求:
我们使用嵌入式反演,有:
因此:
- (3)求:
即:
另 \(d=kd\) ,枚举新的 \(d\):
将预处理 \(\mu(d)\) 的前缀和改为预处理 \(\sum_{k \in prime,k|d}^{min(n,m)}\limits \mu(d/k)\) 即可。
- (4)求:
显然:
如果对 \(\lfloor \frac n{kd} \rfloor\) 整除分块,分别对每个 \(d\) 求出对应的 \(\sum_{d=1}^{n/k}\limits\mu(d) \lfloor \frac n{kd} \rfloor^2)\),时间复杂度就是 \(O(n \sqrt n)\) 的。
我们可以直接对 \(n/k\) 整除分块,求出 \(\prod_{k=1}^{n}k^{-2*(\sum_{d=1}^{n/k}\limits\mu(d) \lfloor \frac n{kd} \rfloor^2)}\) ,时间复杂度就约为 \(O(\sqrt n*\sqrt n)=O(n)\)
- (5)求:
有等式:
对于每一个质因数讨论,令 \(k_x\) 表示最大的 \(prime^k|x\)。
用 \(d\) 表示所枚举的约数,设 \(k_i>k_j\)。
那么若\(k_y=0\),则 \(k_d=k_x\) ,若 \(k_x=0\),则 \(k_d=k_i+k_y\)。
显然这样可以表示出所有约数,等式成立。
整除分块即可
- (6)求:
考虑一般做法,有:
令 \(T=td\):
除此之外,还有一种比较有意思的解法:
定义一种运算 \((f\oplus g)(x) = \prod\limits_{d\mid x} f(d)^{g(\frac xd)}\)
令 \(*\) 为狄利克雷卷积,有:
进而有一种基于 \(\prod\) 的莫比乌斯反演:
即:
进而,令 \(g=f*\mu\),有 \(f(x)=\prod_{d|x}g(x)\) :
\(O(n\ln n)\) 预处理 \(g\) 即可。
[SDOI2008] 仪仗队
#include<bits/stdc++.h>
using namespace std;
int q;
long long mu[50005];
int pri[50005],top;
bool vis[50005];
inline void init(){
mu[1]=1;
for(int i=2;i<=5e4;i++){
if(!vis[i])pri[++top]=i,mu[i]=-1;
for(int j=1;j<=top&&pri[j]*i<=5e4;j++){
vis[i*pri[j]]=1;
if(i%pri[j]==0)break;
mu[i*pri[j]]=-mu[i];
}
}for(int i=1;i<=5e4;i++)mu[i]+=mu[i-1];
}
inline long long solve(int n,int m){
long long res=0;
for(int l=1,r=0;l<=n&&l<=m;l=r+1){
r=min(n/(n/l),m/(m/l));
res+=1ll*(mu[r]-mu[l-1])*(n/l)*(m/l);
}return res;
}
int main(){
init();
scanf("%d",&q);if(q==1){puts("0");return 0;}
printf("%lld",solve(q-1,q-1)+2);
// scanf("%d",&q);
// while(q--){
// int n,m;
// scanf("%d%d",&n,&m);
// }
return 0;
}
[POI2007]ZAP-Queries
#include<bits/stdc++.h>
using namespace std;
int q;
long long mu[50005];
int pri[50005],top;
bool vis[50005];
inline void init(){
mu[1]=1;
for(int i=2;i<=5e4;i++){
if(!vis[i])pri[++top]=i,mu[i]=-1;
for(int j=1;j<=top&&pri[j]*i<=5e4;j++){
vis[i*pri[j]]=1;
if(i%pri[j]==0)break;
mu[i*pri[j]]=-mu[i];
}
}for(int i=1;i<=5e4;i++)mu[i]+=mu[i-1];
}
inline long long solve(int n,int m,int d){
long long res=0;
for(int l=1,r=0;l<=n&&l<=m;l=r+1){
r=min(n/(n/l),m/(m/l));
res+=1ll*(mu[r]-mu[l-1])*(n/l/d)*(m/l/d);
}return res;
}
int main(){
init();
scanf("%d",&q);
while(q--){
int n,m,d;
scanf("%d%d%d",&n,&m,&d);
printf("%lld\n",solve(n,m,d));
}
return 0;
}
YY的GCD
#include<bits/stdc++.h>
using namespace std;
int t,n,m;
long long mu[10000005],sum[10000005],f[10000005];
int pri[10000005],top;
bool vis[10000005];
inline void init(){
mu[1]=1;
for(int i=2;i<=1e7;i++){
if(!vis[i])pri[top++]=i,mu[i]=-1;
for(int j=0;j<top&&i*pri[j]<=1e7;j++){
vis[i*pri[j]]=1;
if(i%pri[j]==0)break;
mu[i*pri[j]]=-mu[i];
}
}
for(int i=0;i<top;i++){
for(int j=1;j*pri[i]<=1e7;j++)f[j*pri[i]]+=mu[j];
}
for(int i=1;i<=1e7;i++)sum[i]=sum[i-1]+f[i];
}
long long solve(){
long long res=0;
if(n>m)swap(n,m);
for(int l=1,r=0;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
res+=(sum[r]-sum[l-1])*(n/l)*(m/l);
}return res;
}
int main(){
init();//puts("000");
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
printf("%lld\n",solve());
}
return 0;
}
Product
#include<bits/stdc++.h>
using namespace std;
long long fac;
const long long md=104857601,phi=104857600;
int pri[1000005],top,mu[1000005];
bool vis[1000005];
inline void init(int n){
mu[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i])pri[++top]=i,mu[i]=-1;
for(int j=1;j<=top&&i*pri[j]<=n;j++){
vis[i*pri[j]]=1;
if(i%pri[j]==0)break;
mu[i*pri[j]]=-mu[i];
}
}
fac=1;
for(int i=1;i<=n;i++)fac=fac*i%md;
for(int i=1;i<=n;i++)mu[i]+=mu[i-1];
}
inline long long pwr(long long x,long long y){
long long res=1;
while(y){
if(y&1)res=res*x%md;
x=x*x%md;y>>=1;
}return res;
}
inline long long calc2(int n){
long long res=0;
for(int l=1,r=0;l<=n;l=r+1){
r=n/(n/l);
res=(res+1ll*(n/l)*(n/l)%phi*(mu[r]-mu[l-1]))%phi;
}return (res+phi)%phi;
}
inline long long calc(int n){
long long res=1;
for(int l=1,r=0;l<=n;l=r+1){
r=n/(n/l);fac=1;
for(int i=l;i<=r;i++)fac=fac*i%md;
res=res*pwr(fac*fac%md,calc2(n/l))%md;
}return res;
}
int main(){
int n;
scanf("%d",&n);
init(n);
long long ans=pwr(fac*fac%md,n);
printf("%lld",ans*pwr(calc(n),md-2)%md);
return 0;
}
[SDOI2015]约数个数和
#include<bits/stdc++.h>
using namespace std;
int T;
long long mu[50005],s[50005];
int pri[50005],top;
bool vis[50005];
inline void init(){
mu[1]=1;
for(int i=2;i<=50000;i++){
if(!vis[i])pri[++top]=i,mu[i]=-1;
for(int j=1;j<=top&&i*pri[j]<=50000;j++){
vis[i*pri[j]]=1;
if(i%pri[j]==0)continue;
mu[i*pri[j]]=-mu[i];
}mu[i]+=mu[i-1];
}
for(int i=1;i<=50000;i++){
for(int l=1,r;l<=i;l=r+1){
r=i/(i/l);
s[i]+=i/l*(r-l+1);
}
}
}
inline long long solve(int n,int m){
long long res=0;
for(int l=1,r;l<=n&&l<=m;l=r+1){
r=min(n/(n/l),m/(m/l));
res+=(mu[r]-mu[l-1])*s[n/l]*s[m/l];
}return res;
}
int main(){
scanf("%d",&T);init();
while(T--){
int n,m;
scanf("%d%d",&n,&m);
printf("%lld\n",solve(n,m));
}
return 0;
}
[SDOI2017]数字表格
#include<bits/stdc++.h>
using namespace std;
int T;
int f[1000005],fac[1000005],inv[1000005];
const int md=1e9+7;
inline int pwr(int x,long long y){
int res=1;
while(y){
if(y&1)res=1ll*res*x%md;
x=1ll*x*x%md;y>>=1;
}return res;
}
int sum[1000005],isum[1000005],mu[1000005];
int pri[1000005],top;
bool vis[1000005];
inline void init(){
fac[0]=fac[1]=f[1]=mu[1]=1;
for(int i=2;i<=1e6;i++)f[i]=(f[i-1]+f[i-2])%md;
for(int i=2;i<=1e6;i++)fac[i]=1ll*fac[i-1]*f[i]%md;
inv[1000000]=pwr(fac[1000000],md-2);
for(int i=1e6-1;i;i--)inv[i]=1ll*inv[i+1]*f[i+1]%md;
for(int i=1;i<=1e6;i++)inv[i]=1ll*inv[i]*fac[i-1]%md;
for(int i=2;i<=1e6;i++){
if(!vis[i])pri[++top]=i,mu[i]=-1;
for(int j=1;j<=top&&i*pri[j]<=1e6;j++){
vis[i*pri[j]]=1;
if(i%pri[j]==0)break;
mu[i*pri[j]]=-mu[i];
}
}
for(int i=0;i<=1e6;i++)sum[i]=1;
for(int i=0;i<=1e6;i++)isum[i]=1;
for(int i=1;i<=1e6;i++){
for(int j=i;j<=1e6;j+=i){
if(mu[j/i]==1)sum[j]=1ll*sum[j]*f[i]%md,isum[j]=1ll*isum[j]*inv[i]%md;
if(mu[j/i]==-1)sum[j]=1ll*sum[j]*inv[i]%md,isum[j]=1ll*isum[j]*f[i]%md;
}
}
for(int i=1;i<=1e6;i++)sum[i]=1ll*sum[i]*sum[i-1]%md;
for(int i=1;i<=1e6;i++)isum[i]=1ll*isum[i]*isum[i-1]%md;
}
inline int solve(int n,int m){
int res=1;
for(int l=1,r=0;l<=n&&l<=m;l=r+1){
r=min(n/(n/l),m/(m/l));
res=1ll*res*pwr(1ll*sum[r]*isum[l-1]%md,1ll*(m/l)*(n/l)%(md-1))%md;
}
return res;
}
int main(){
init();
scanf("%d",&T);
while(T--){
int n,m;scanf("%d%d",&n,&m);
printf("%d\n",solve(n,m));
}
return 0;
}