日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

积性函数与线性筛

發布時間:2023/12/15 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 积性函数与线性筛 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

積性函數與線性篩

積性函數

線性篩素數
保證每個數只會被它的最小質因子給篩掉(不同于埃氏篩中每個數會被它所有質因子篩一遍從而使復雜度過高)

int pri[N],tot,zhi[N];//zhi[i]為1的表示不是質數 void sieve() {zhi[1]=1;for (int i=2;i<=n;i++){if (!zhi[i]) pri[++tot]=i;for (int j=1;j<=tot&&i*pri[j]<=n;j++){zhi[i*pri[j]]=1;if (i%pri[j]==0) break;}} }

所有線性篩積性函數都必須基于線性篩素數。

線性篩莫比烏斯函數

int mu[N],pri[N],tot,zhi[N]; void sieve() {zhi[1]=mu[1]=1;for (int i=2;i<=n;i++){if (!zhi[i]) pri[++tot]=i,mu[i]=-1;for (int j=1;j<=tot&&i*pri[j]<=n;j++){zhi[i*pri[j]]=1;if (i%pri[j]) mu[i*pri[j]]=-mu[i];else {mu[i*pri[j]]=0;break;}}} }

線性篩歐拉函數

int phi[N],pri[N],tot,zhi[N]; void sieve() {zhi[1]=phi[1]=1;for (int i=2;i<=n;i++){if (!zhi[i]) pri[++tot]=i,phi[i]=i-1;for (int j=1;j<=tot&&i*pri[j]<=n;j++){zhi[i*pri[j]]=1;if (i%pri[j]) phi[i*pri[j]]=phi[i]*phi[pri[j]];else {phi[i*pri[j]]=phi[i]*pri[j];break;}}} }

線性篩約數個數
記d(i)表示i的約數個數
d(i)=∏ki=1(ai+1)
維護每一個數的最小值因子出現的次數(即a1)即可

int d[N],a[N],pri[N],tot,zhi[N]; void sieve() {zhi[1]=d[1]=1;for (int i=2;i<=n;i++){if (!zhi[i]) pri[++tot]=i,d[i]=2,a[i]=1;for (int j=1;j<=tot&&i*pri[j]<=n;j++){zhi[i*pri[j]]=1;if (i%pri[j]) d[i*pri[j]]=d[i]*d[pri[j]],a[i*pri[j]]=1;else {d[i*pri[j]]=d[i]/(a[i]+1)*(a[i]+2);a[i*pri[j]]=a[i]+1;break;}}} }

線性篩約數和
記σ(i)表示i的約數和
σ(i)=∏ki=1(∑aij=0pji)
維護low(i)表示i的最小質因子的指數次冪,即pa11,sum(i)表示i的最小質因子對答案的貢獻,即∑a1j=0pj1
(這玩意兒可能會爆int吧,我這里就不管那么多了)

int low[N],sum[N],sigma[N],pri[N],tot,zhi[N]; void sieve() {zhi[1]=low[1]=sum[1]=sigma[1]=1;for (int i=2;i<=n;i++){if (!zhi[i]) low[i]=pri[++tot]=i,sum[i]=sigma[i]=i+1;for (int j=1;j<=tot&&i*pri[j]<=n;j++){zhi[i*pri[j]]=1;if (i%pri[j]==0) {low[i*pri[j]]=low[i]*pri[j];sum[i*pri[j]]=sum[i]+low[i*pri[j]];sigma[i*pri[j]]=sigma[i]/sum[i]*sum[i*pri[j]];break;}low[i*pri[j]]=pri[j];sum[i*pri[j]]=pri[j]+1;sigma[i*pri[j]]=sigma[i]*sigma[pri[j]];}} }

線性篩一般積性函數
若想線性篩出積性函數f(x),就必須能夠快速計算出一下函數值:

1、f(1)
2、f§(p是質數)
3、f(pk)(p是質數)
其實就是含有的質因子數小于等于1的所有數對應的函數值。

常見的積性函數都會給出上述函數值的有關定義。對于自定義的一個積性函數(如狄利克雷卷積),就需要自行計算出上述函數值。

我們假設已經完成了上述函數值的計算,現在要求篩出所有至少含有兩個質因子的數對應的函數值。
顯然,一個含有至少兩個質因子的數一定可以被分解成兩個互質的且均不為1的數的乘積。此時我們就可以用f(xy)=f(x)f(y)計算得出相應的函數值。

以下內容需要完全理解上面的線性篩素數。

我們考慮篩的過程中,i?prij會被i乘上prij給篩掉。
若將i唯一分解得到pa11pa22…pakk,則一定有prij<=p1。
這個不需要證明,因為當prij=p1的時候就break掉了。

若prij<p1,則prij與i互質,可以直接f(i?prij)=f(i)?f(prij)
若prij=p1,這時就需要對i記錄一個lowi,表示i中最小值因子的指數次冪,即lowi=pa11(就是在唯一分解中的那個pa11)。
如果使用i除掉lowi那么結果中的最小質因子一定大于p1,而又因為prij=p1,從而可知gcd(i/lowi,lowi?prij)=1。那么就可以f(i?prij)=f(i/lowi)?f(lowi?prij)
注意當lowi=i時表示這個數是一個質數的若干次冪,這個時候就需要用到上方的特殊定義。

void sieve() {zhi[1]=low[1]=1;f[1]=1直接定義;for (ll i=2;i<=n;i++){if (!zhi[i]) low[i]=pri[++tot]=i,f[i]=對質數直接定義;for (ll j=1;j<=tot&&i*pri[j]<=n;j++){zhi[i*pri[j]]=1;if (i%pri[j]==0){low[i*pri[j]]=low[i]*pri[j];if (low[i]==i)f[i*pri[j]]=對質數的若干次冪進行定義(一般由f[i]遞推);elsef[i*pri[j]]=f[i/low[i]]*f[low[i]*pri[j]];break;}low[i*pri[j]]=pri[j];f[i*pri[j]]=f[i]*f[pri[j]];}} }

此外
對于某種形如狄利克雷卷積形式的函數∑d|xf(d)g(xd),若其中f(x)或g(x)不是積性函數,對于數據范圍較小(如106)的時候可以考慮暴力篩,即枚舉一個d去計算可以給哪些x做貢獻,復雜度是O(∑ni=1?ni?)即埃篩的復雜度。若數據范圍較大(107埃篩跑不過)就需要去考慮這個函數的一些相關性質了。

博客源地址https://www.cnblogs.com/zhoushuyu/p/8275530.html

總結

以上是生活随笔為你收集整理的积性函数与线性筛的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。