淺談演算法——莫比烏斯反演

來源:互聯網
上載者:User

標籤:namespace   break   資料   cas   pac   ring   rom   十分   geo   

前言

莫比烏斯反演(又稱懵逼鎢絲繁衍),那種讓人看了就懵逼的東西(其實是我太菜了)
莫比烏斯反演在知道之後對解題十分有協助,\(O(n)\)的柿子分分鐘化成\(O(\sqrt n)\)
那麼,什麼是莫比烏斯反演呢?

莫比烏斯反演

1.莫比烏斯反演
如果說,有\(f(n)\)和\(g(n)\)是定義在正整數集合上的兩個函數,並且滿足
\[f(n)=\sum\limits_{d|n} g(d)\]
那麼就有
\[g(n)=\sum\limits_{d|n} f(\dfrac{n}{d})\times \mu(d)\]
這個變形也就是莫比烏斯反演

2.莫比烏斯函數(性質/證明)
對於任意整數n,滿足
\[\sum\limits_{d|n} \mu(d)=\begin{cases}1&,n=1\\0&,n>1\end{cases}\]
證明:

  • n=1時顯然
  • n>1時,設\(n=P_1^{x_1}\times P_2^{x_2}\times ...\times P_k^{x_k}\),其中\(P_i(1\leqslant i\leqslant k)\)為n的互質因子,我們設\(d=P_1^{y_1}\times P_2^{y_2}\times ...\times P_k^{y_k}\),其中\(0\leqslant y_i\leqslant x_i(1\leqslant i\leqslant k)\),當存在一個\(y_i\geqslant2\)的話,那麼\(\mu(d)=0\),因此我們只要考慮\(y_i=0,1\)的情況。假設d中含有r個n的互質因子,且這些質因子的指數為1,那麼\(\mu(d)=(-1)^r\),這樣的d一共有\(\binom{k}{r}\)個。
    那麼\(\sum\limits_{d|n} \mu(d)=\sum\limits_{r=0}^k \binom{k}{r}\times (-1)^r=(1-1)^k=0\)

莫比烏斯函數\(\mu(n)\)是個積性函數,證明略。
這說明\(\mu(n)=\prod\limits_{i=1}^k \mu(P_i^{x_i})\)

由於莫比烏斯函數的這些性質,使得它可以用歐拉篩線上性時間內求出

3.莫比烏斯反演(性質/證明)
首先我們證明一下第一個柿子的正確性
\[g(n)=\sum\limits_{d|n}f(\dfrac{n}{d})\times \mu(d)=\sum\limits_{d|n}\mu(d) \sum\limits_{i|\frac{n}{d}}g(i)\Longrightarrow\sum\limits_{i|n}g(i)\sum\limits_{i\times d|n}\mu(d)=\sum\limits_{i|n}g(i)\sum\limits_{d|\frac{n}{i}}\mu(d)\]
箭頭轉換的時候,將\(g(i)\)提前枚舉了
我們現在考慮一下\(\sum\limits_{d|\frac{n}{i}}\mu(d)\)的取值

  • 當i=n時,\(\sum\limits_{d|\frac{n}{i}}\mu(d)=1,g(i)\sum\limits_{d|\frac{n}{i}}\mu(d)=g(n)\)
  • 當i為小於n的約數時,\(\sum\limits_{d|\frac{n}{i}}\mu(d)=0,g(i)\sum\limits_{d|\frac{n}{i}}\mu(d)=0\)

所以\(g(n)=\sum\limits_{d|n}f(\dfrac{n}{d})\times \mu(d)\)得證

莫比烏斯函數有個性質:
當\(f(n)/g(n)\)中的任意一個為積性函數後,另一個也同樣為積性函數
這個性質保證了其在之後能夠進行線篩。
證明略(證明太長,我懶得寫)

4.莫比烏斯函數的應用

  • \(g(i)\)很難直接求,但\(\sum\limits_{d|i}g(d)\)很好求,我們就可以用莫比烏斯反演來求\(g(i)\):\[f(i)=\sum\limits_{d|i}g(d)\Rightarrow g(i)=\sum\limits_{d|i}f(\dfrac{i}{d})\times \mu(d)\]
  • \(g(i)\)很難直接求,但\(\sum\limits_{d=1}^{\frac{n}{i}}\)很好求,我們就可以用莫比烏斯反演來求\(g(i)\):\[f(i)=\sum\limits_{d=1}^{\frac{n}{i}}g(d\times i)\Rightarrow g(i)=\sum\limits_{d=1}^{\frac{n}{i}}f(d\times i)\mu(d)\]
例題

[POI2007]Zap
Description
FGD正在破解一段密碼,他需要回答很多類似的問題:對於給定的整數a,b和d,有多少正整數對x,y,滿足x<=a,y<=b,並且gcd(x,y)=d。作為FGD的同學,FGD希望得到你的協助。

Input
第一行包含一個正整數n,表示一共有n組詢問。(1<=n<= 50000)接下來n行,每行表示一個詢問,每行三個正整數,分別為a,b,d。(1<=d<=a,b<=50000)

Output
對於每組詢問,輸出到輸出檔案zap.out一個正整數,表示滿足條件的整數對數。

Sample Input
2
4 5 2
6 4 3

Sample Output
3
2

HINT
對於第一組詢問,滿足條件的整數對有(2,2),(2,4),(4,2)。對於第二組詢問,滿足條件的整數對有(6,3),(3,3)。

Attention:為了方便書寫,我們把x,y改成i,j,把多組資料的n改為T,把a,b改成n,m,並且我們讓n<m

首先我們列出本題要求的柿子
\[\sum\limits_{i=1}^n\sum\limits_{j=1}^m[gcd(i,j)==d]\]
d看起來太討厭,我們把它直接除掉
\[\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{m}{d}\rfloor}[gcd(i,j)==1]\]
然後我們發現最後面那一個長得和莫比烏斯函數很像,稍微改一下得到
\[\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{m}{d}\rfloor}\sum\limits_{x|i,x|j}\mu(x)\]
把枚舉x的挪到前面
\[\sum\limits_{x=1}^{\lfloor\frac{n}{d}\rfloor}\mu(x)\lfloor\dfrac{n}{dx}\rfloor\lfloor\dfrac{m}{dx}\rfloor\]
這個柿子終於變得小清新了,但是如果直接枚舉x的話還是擺脫不了TLE的命運。。。
注意到後面的\(\lfloor\dfrac{n}{dx}\rfloor\lfloor\dfrac{m}{dx}\rfloor?\)在很多情況下值都是一樣的,那麼我們進行數論分塊即可
總時間複雜度降為\(O(T\sqrt n)\)

/*program from Wolfycz*/#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define inf 0x7f7f7f7fusing namespace std;typedef long long ll;typedef unsigned int ui;typedef unsigned long long ull;inline int read(){    int x=0,f=1;char ch=getchar();    for (;ch<‘0‘||ch>‘9‘;ch=getchar())  if (ch==‘-‘)    f=-1;    for (;ch>=‘0‘&&ch<=‘9‘;ch=getchar())    x=(x<<1)+(x<<3)+ch-‘0‘;    return x*f;}inline void print(int x){    if (x>=10)     print(x/10);    putchar(x%10+‘0‘);}const int N=5e4;int prime[N+10],miu[N+10],sum[N+10];bool inprime[N+10];void prepare(){    miu[1]=1;    int tot=0;    for (int i=2;i<=N;i++){        if (!inprime[i])    prime[++tot]=i,miu[i]=-1;        for (int j=1;j<=tot&&i*prime[j]<=N;j++){            inprime[i*prime[j]]=1;            if (i%prime[j]==0){miu[i*prime[j]]=0;break;}            miu[i*prime[j]]=-miu[i];        }    }    for (int i=1;i<=N;i++)  sum[i]=sum[i-1]+miu[i];}int main(){    prepare();    for (int Data=read();Data;Data--){        int A=read(),B=read(),D=read();        ll Ans=0;        A/=D,B/=D;        int x=min(A,B),pos=0;        for (int d=1;d<=x;d=pos+1){            pos=min(A/(A/d),B/(B/d));            Ans+=1ll*(sum[pos]-sum[d-1])*(A/d)*(B/d);        }        printf("%lld\n",Ans);    }    return 0;}

淺談演算法——莫比烏斯反演

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.