莫比烏斯函數的定義:
μ(x)=⎩⎪⎨⎪⎧1,n=1(−1)k,n=p1p2...pk,其中p1,p2,...,pk爲互不相同的素數0,其他情況
自己稍微推一推就可以知道這是一個積性函數。
所以很顯然我們可以線性篩μ
由定義得:
μ(1)=1
μ(p)=−1
μ(pk)=0(k>1)
所以就可以直接篩了,代碼如下:
void init(){
mu[1]=1;
for(int i=2;i<N;i++){
if(!vis[i]){
prm[cnt++]=i;
mu[i]=-1;
}
for(int j=1;j<cnt&&i*prm[j]<N;j++){
vis[i*prm[j]]=1;
if(!(i%prm[j])){
mu[i*prm[j]]=0;
break;
}
mu[i*prm[j]]=-mu[i];
}
}
return;
}
莫比烏斯反演
莫比烏斯反演有一個非常非常非常重要的性質:
∑d∣nμ(d)=[n=1]
怎麼證?
我們設n=∏i=1kpiαi
考慮n的所有因數,他們的素因子都是p0,p1,...,pk−1中的,而我們會發現只有當因數的所有的素因子次數爲1時對答案的貢獻纔不爲0,所以我們可以認爲n的每個對答案的貢獻不爲0因數都是在p0,p1,...,pk−1中取若干個素數相乘得到的。特殊的,因數1我們可以當做一個素數都不取。
當n=1時,顯然原式=1。
當n>1時,
若k爲奇數,
首先易證Cnm=Cnn−m
選奇數個素數相乘得到的因數個數爲Ck1+Ck3+...+Ckk,這種因數的函數值爲−1
選偶數個素數相乘得到的因數個數爲Ck0+Ck2+...+Ckk−1,這種因數的函數值爲1
首先顯然Cnm=Cnn−m
所以易證Ck1+Ck3+...+Ckk=Ck0+Ck2+...+Ckk−1,所以因數的函數值加起來爲0。
若k爲偶數,
選奇數個素數相乘得到的因數個數爲Ck1+Ck3+...+Ckk−1,這種因數的函數值爲−1
選偶數個素數相乘得到的因數個數爲Ck0+Ck2+...+Ckk,這種因數的函數值爲1
首先顯然Cnm=Cn−1m−1+Cn−1m(m̸=0),Cn0=Cn−10
所以Ck0+Ck2+...+Ckk=Ck−10+Ck−11+Ck−12+...+Ck−1k−2+Ck−1k−1=2k−1
Ck1+Ck3+...+Ckk−1=Ck1+Ck2+Ck3+...+Ckk−(Ck0+Ck2+...+Ckk)
=2k−(Ck0+Ck2+...Ckk)=2k−2k−1=2k−1=Ck0+Ck2+...Ckk
所以因數的函數值加起來爲0。
綜上,∑d∣nμ(d)=[n=1]
這個性質有多重要,我們接下來看一道題(前置知識:數論分塊):
有t(1≤t≤10000)組數據,每組數據給定n,m,(1≤n≤m≤107)求i=1∑nj=1∑m[gcd(i,j)=1]
O(nm)秒了
我們會發現暴力的時間複雜度是O(nm),顯然會TLE,所以我們考慮優化。
[gcd(i,j)=1]這個式子很神奇?所以就從這裏入手。
仔細分析就會發現[gcd(i,j)=1]=d∣gcd(i,j)∑μ(d),因爲由前面的莫比烏斯函數的性質可得當且僅當gcd(i,j)=1時,∑d∣gcd(i,j)μ(d)纔會等於1,否則等於0
所以原式就可以變成:i=1∑nj=1∑md∣gcd(i,j)∑μ(d)
然後枚舉d,此時i,j就是d的倍數,所以小於n的i就有⌊dn⌋個,j同理。所以我們就可以輕鬆得到:d=1∑n⌊dn⌋⌊dm⌋μ(d)
線性篩出μ的前綴和,然後數論分塊O(n+m)求解。
這就是莫比烏斯反演(其實有個公式的,但是用這個公式大部分題目都很難推,所以不如直接用莫比烏斯函數的性質來搞)
莫比烏斯反演只有多推才能熟練,所以
我們繼續!
有t(1≤t≤10000)組數據,每組數據給定n,m,k(1≤n≤m≤107).求:i=1∑nj=1∑m[gcd(i,j)=k](HDU1695數據範圍稍有增加)
咋一看和剛剛的怎麼長得那麼像?
我們會發現只有當i,j都是k的倍數時,且gcd(ki,kj)=1時才能成立
所以原式轉化爲i=1∑⌊kn⌋i=1∑⌊km⌋[gcd(i,j)=1]
這不就轉化爲原來的那道題了嗎?得到原式等於d=1∑⌊kn⌋⌊dkn⌋⌊dkm⌋μ(d)
直接數論分塊
接着下一題:
有t(1≤t≤10000)組數據,每組數據給定n,m(1≤n≤m≤107)求i=1∑nj=1∑m[gcd(i,j)爲素數]
(bzoj2820)
咋一看怎麼和剛剛的還是那麼像?
記素數集爲prime
所以我們直接枚舉素數,得到p∈prime∑i=1∑nj=1∑m[gcd(i,j)=p]
由上題可得:原式=p∈prime∑d=1∑pn⌊pdn⌋⌊pdm⌋μ(d)
然後我們記k=pd,枚舉k,得到:
k=1∑n⌊kn⌋⌊km⌋p∈prime,p∣k∑μ(pk)
設函數f(n)=∑p∈prime,p∣nμ(pn)
所以原式=k=1∑n⌊kn⌋⌊km⌋f(k)
我們可以在線性篩的時候處理f(n)。
當n爲素數時,顯然f(n)=1
當n爲合數時,
記prm[j]爲n的最小素因子(線性篩中當前枚舉的素數),i=pn
當prm[j]∣i(n的最小素因子prm[j]的次數大於1)時,
當i無多個次數大於1的素因子時,當且僅當p=prm[j]時μ(pn)̸=0,此時f(n)=μ(prm[j]n)=μ(i)
當i有多個次數大於1的素因子時,無論prm[j]等於多少,μ(pn)=0,又因爲易知μ(i)=0,所以f(n)=μ(pn)=0=μ(i),
所以當prm[j]∣i時f(n)=μ(i)
當prm[j]̸∣i(n的最小素因子prm[j]的次數等於1)時,
此時,n就比i多了一個素因數prm[j],因爲
f(i)=p∣i,p∈prime∑μ(pi)
f(n)=p∣n,p∈prime∑μ(pn)=p∣n,p∈prime∑μ(pi∗prm[j])
因爲i不含素因子prm[i],所以
μ(pi∗prm[j])=−μ(pi)
又因爲n比i多一個素因子prm[j],所以
f(n)=−p∣n,p∈prime,p̸=prm[j]∑μ(pi)+μ(prm[j]n)
=μ(i)−p∣i,p∈prime∑μ(pi)
=μ(i)−f(i)
這樣我們就可以在線性篩的時候預處理f,然後直接數論分塊解決。
繼續
有t(1≤t≤1000000)組數據,每組數據給定n,m,k(1≤n≤107)求i=1∑ngcd(i,n)
前置知識:狄利克雷卷積
首先枚舉gcd(i,n):
d∣n∑di=1∑n[gcd(i,n)=d]
除掉d得到:
d∣n∑di=1∑dn[gcd(i,dn)=1]
反演:
d∣n∑di=1∑dnk∣i,k∣dn∑μ(k)
枚舉k:
d∣n∑k∣dn∑dμ(k)dkn
我們記T=dk,然後枚舉T:
T∣n∑Tnd∣T∑dμ(dT)
記g(n)=n,f(n)=∑d∣ndμ(dn)
顯然g是積性函數
然後我們發現f是g和μ的狄利克雷卷積,所以也是積性函數
然後我們發現原式其實也就是f和g的狄利克雷卷積,所以也是一個積性函數
直接線性篩,然後O(1)詢問。
其實還有一種更簡單的做法,需要用到歐拉函數的性質∑d∣nϕ(d)=n
利用這個性質我們就可以吧原式轉化爲:
i=1∑nd∣i,d∣n∑ϕ(d)
直接枚舉d,就可以直接得到
d∣n∑ϕ(d)dn
這顯然是狄利克雷卷積的形式,是一個積性函數,直接線性篩就OK了。
再看一道題
有t(1≤t≤10000)組數據,每組數據給定n,m,k(1≤n≤m≤107).求:i=1∑nj=1∑mgcd(i,j)
這道題和剛剛有點像?
還是先枚舉gcd(i,j):
d=1∑ndi=1∑nj=1∑m[gcd(i,j)=d]
通過之前第二題的結論可以得到:
d=1∑ndk=1∑n⌊dkn⌋⌊dkm⌋μ(k)
我們令T=dk,然後直接枚舉T:
T=1∑n⌊Tn⌋⌊Tm⌋d∣T∑dμ(dT)
記f(n)=∑d∣Tdμ(dT),顯然是狄利克雷卷積的形式,是一個積性函數,可以直接線性篩。
所以原式可以轉化爲:
T=1∑n⌊Tn⌋⌊Tm⌋f(T)
直接數論分塊O(n+m)
這道題同樣也可以用歐拉函數,而且同樣簡單很多
原式可以直接轉化爲
i=1∑nj=1∑md∣i,d∣j∑ϕ(d)
直接枚舉d:
d=1∑nϕ(d)⌊dn⌋⌊dm⌋
然後數論分塊就OK了。
就是這麼簡單。
那幹嘛要講莫比烏斯反演的做法?
練手感…因爲很多題都是隻能用莫比烏斯反演做的,比如說下一題:
有t(1≤t≤1000000)組數據,每組數據給定n,m,k(1≤n≤107)求i=1∑nlcm(i,n)
先講一種用歐拉函數的O(nlogn)做法(當然在這道題會TLE,但是可以瞭解一下,這種做法非常神奇)
i=1∑nlcm(i,n)
=ni=1∑ngcd(i,n)i
=nd∣n∑d1i=1∑ni[gcd(i,n)=d]
=nd∣n∑d1i=1∑dnid[gcd(i,dn)=1]
=nd∣n∑i=1∑dni[gcd(i,dn)=1]
=nd∣n∑2dϕ(d)+[d=1]
前面幾行應該都懂了吧,都做了那麼多題了
問題是最後一行…
我們只考慮後面的式子:∑i=1dni[gcd(i,dn)=1]
因爲d是n的因數,所以我們可以用d代替dn:
i=1∑di[gcd(i,d)=1]
其實就是求小於等於d與d互質的數的和
然後我們會發現如果x⊥d(x<d),那麼(d−x)⊥d
所以我們可以把與d互質的數首尾兩兩分組,他們的和就是d,然後他們所有的和就是2dϕ(d),如果x=d−x也不影響,特判一下d=1的情況就OK了。
然後線性篩出ϕ,調和級數時間預處理答案。
但是這道題要O(n)纔行啊,有更優秀的做法嗎?
莫比烏斯反演
i=1∑nlcm(i,n)
=ni=1∑ngcd(i,n)i
=nd∣n∑d1i=1∑ni[gcd(i,n)=d]
=nd∣n∑d1i=1∑dnid[gcd(i,dn)=1]
=nd∣n∑i=1∑dni[gcd(i,dn)=1]
=nd∣n∑i=1∑dnik∣i,k∣dn∑μ(k)
=nd∣n∑k∣dn∑μ(k)ki=1∑dkni
=nk∣n∑μ(k)kd∣kn∑i=1∑di
後面那個式子用等差數列求和:
=nk∣n∑μ(k)kd∣kn∑2d(d+1)
=2nk∣n∑μ(k)kd∣kn∑(d2+d)
我們記f(n)=∑k∣nμ(k)k∑d∣knd2,g(n)=∑k∣nμ(k)k∑d∣knd
可以輕鬆證明這兩個都是積性函數,可以線性篩。
然後就OK了。
留一道題給讀者思考:
【BZOJ2693】jzptab