定义
本文中默认将正整数 $n$ 分解质因数得到 $n=\prod_{i=1}^{m} p_i^{c_i}$。
莫比乌斯函数的定义为:
翻译成中文就是:
- 当 $n=1$ 时,$\mu(n)=1$
- 当 $n$ 存在次数大于等于 $2$ 的质因子时,$\mu(n)=0$
- 否则当 $n$ 的所有质因子次数都为 $1$ 时,$\mu(n)=(-1)^m$。
性质
性质1
$\mu$ 为积性函数,即若 $(a,b)=1$,则 $\mu(ab)=\mu(a)\mu(b)$。
最暴力的证法就是把 $a,b$ 各分三类,分讨可证。总之非常显然。
性质2
证明老师上课好像没讲,就参考 OI-wiki 的证法了:
设 $n’=\prod_{i=1}^{m} p_i$,则:
基于这个性质,我们可以将 $[(i,j)=1]$ 进行转化:
线性求 $\mu$
与 $\varphi$ 求法相似,基于线性筛可以 $O(n)$ 求出。
C++
const int N=1e6;
vi prm,v(N+1),mu(N+1);
mu[1]=1;
for(int i=2;i<=N;i++){
if(!v[i])prm.eb(i),v[i]=i,mu[i]=-1;
for(auto p:prm){
if(i*p>N||v[i]<p)break;
v[i*p]=p;
mu[i*p]=(mu[i]==0||i%p==0?0:-mu[i]);
}
}莫比乌斯反演
木莫木反(确信
莫比乌斯反演如下:
证明如下:
其中倒数第三行到倒数第二行利用上述的性质2进行转化。
例题
例题1(P3704)
题目大意:
$T(1\le T\le 3000)$ 组数据,每次给定 $n,m(1\le n,m\le 1\times 10^6)$,求:
其中 $f(x)$ 表示菲波那切数列第 $i$ 项。
这道题用莫比乌斯函数直接推式子,不妨设 $n\le m$。
首先容易想到,可以将原问题转化为计算 $f(x)(x\le m)$ 对于答案的贡献,即:
$f(d)$ 的指数可以通过性质2得到:
把指数写成底数的乘积:
设 $t=dx$,则:
其中 $\prod_{d|t}f(d)^{\mu(\frac{t}{d})}$ 的值仅与 $t$ 有关,记为 $G(t)$。则:
$f(x),\mu(x)$ 都可以线性预处理出,$G(x)$ 可以 $O(n)$ 枚举每个数,把它的倍数都乘以对应的值即可 $O(n\log n)$ 预处理。最终每次询问时,使用数论分块进行计算即可。
代码
C++
#include<bits/stdc++.h>
using namespace std;
#define dbg(x) cerr<<#x<<':'<<(x)<<' '
#define dbe(x) cerr<<#x<<':'<<(x)<<endl
#define eb emplace_back
#define ep emplace
#define endl '\n'
using ll=long long;
using vi=vector<int>;
using vl=vector<ll>;
using tp=tuple<int,int>;
const int N=1e6;
template<int Mod>struct modint{
int x;
modint():x(0){}
modint(int x):x(x<0?x+Mod:x){}
modint& operator=(int y){return x=(y<0?y+Mod:y),*this;}
modint operator+(const modint& y){return x+y.x>=Mod?x+y.x-Mod:x+y.x;}
modint operator-(const modint& y){return x-y.x<0?x-y.x+Mod:x-y.x;}
modint operator*(const modint& y){return (ll)x*y.x%Mod;}
modint operator^(int y)const{
if(y>=Mod-1||y<=1-Mod)y%=Mod-1;
if(y<0)y+=Mod-1;
modint ans=1,a=*this;
while(y){
if(y&1)ans=ans*a;
a=a*a;
y>>=1;
}
return ans;
}
modint operator/(const modint& y){return *this*(y^(Mod-2));}
modint& operator+=(const modint& y){return *this=*this+y;}
modint& operator-=(const modint& y){return *this=*this-y;}
modint& operator*=(const modint& y){return *this=*this*y;}
modint& operator^=(int y){return *this=*this^y;}
modint& operator/=(const modint& y){return *this=*this/y;}
bool operator==(const modint& y){return x==y.x;}
bool operator!=(const modint& y){return x!=y.x;}
friend istream& operator>>(istream& is,modint& y){return is>>y.x;}
friend ostream& operator<<(ostream& os,const modint& y){return os<<y.x;}
};
const int P=1e9+7;
using mint=modint<P>;
using vm=vector<mint>;
int main(){
cin.tie(0)->sync_with_stdio(0);
vm fib(N+1);fib[1]=1;
for(int i=2;i<=N;i++)fib[i]=fib[i-1]+fib[i-2];
vi prm,v(N+1),mu(N+1);{
mu[1]=1;
for(int i=2;i<=N;i++){
if(!v[i])prm.eb(i),v[i]=i,mu[i]=-1;
for(auto p:prm){
if(i*p>N||v[i]<p)break;
v[i*p]=p;
mu[i*p]=(mu[i]==0||i%p==0?0:-mu[i]);
}
}
}
vm G(N+1,1);{
G[1]=1;
for(int d=1;d<=N;d++){
for(int i=1;d*i<=N;i++){
G[d*i]*=(fib[d]^mu[i]);
}
}
}
vm qzG(N+1);{
qzG[0]=1;
for(int i=1;i<=N;i++){
qzG[i]=qzG[i-1]*G[i];
}
}
int T;
cin>>T;
while(T--){
int n,m;
cin>>n>>m;
if(n>m)swap(n,m);
mint ans=1;
for(int l=1,r;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
int o=ll(n/l)*(m/l)%(P-1);
ans*=(qzG[r]/qzG[l-1])^o;
}
cout<<ans<<endl;
}
return 0;
}例题2
还没做。
什么雷霆题目