Min_25 篩


Min_25 篩

yyb好神仙啊

干什么用的

可以在\(O(\frac{n^{\frac 34}}{\log n})\)的時間內求積性函數\(f(x)\)的前綴和。

別問我為什么是這個復雜度

要求\(f(p)\)是一個關於\(p\)的簡單多項式,\(f(p^c)\)可以快速計算。

怎么做啊

首先我們需要對每個\(x=\lfloor\frac ni\rfloor\)求出\(\sum_{i=1}^x[i是質數]f(i)\)

怎么求呢?

先線性篩出\(\sqrt n\)范圍內的質數,設\(P_j\)表示從小到大第\(j\)個質數。

\(g(n,j)=\sum_{i=1}^{n}[i \in P \ or\ \min(p)>P_j]f(i)\)

說人話就是:\(i\)是質數,或者\(i\)的最小質因子大於\(P_j\),把\(1-n\)內滿足條件的\(f(i)\)加起來就是\(g(n,j)\)

這個東西的實際含義是什么呢?可以參考一下埃氏篩法的運行過程。

假設現在有\(n\)個數依次排開,第\(i\)個數是\(f(i)\),根據埃氏篩法的那套理論,每次選出一個質數,然后篩掉它的所有倍數。

會發現\(g(n,j)\)就是運行\(j\)次埃氏篩法后,沒被篩掉的所有數之和加上所有的\(f(p)\)

我們要求的\(\sum_{i=1}^x[i是質數]f(i)\)其實就是\(g(x,|P|)\),其中\(|P|\)是質數集合的大小。

考慮\(g(n,j)\)的轉移,分兩種情況:

1、\(P_j^2>n\)。此時運行的第\(j\)次已經不會再篩掉任何數了(因為第\(j\)次運行中篩掉的最小的數是\(P_j^2\)),所以此時\(g(n,j)=g(n,j-1)\)

2、\(P_j^2\le n\)。這時候我們就要考慮哪些數被篩掉了。被篩掉的數一定含有質因子\(P_j\),且除掉\(P_j\)后最小的質因子會大於等於\(P_j\)。考慮減去\(f(P_j)\times g(\frac{n}{P_j},j-1)\),但在\(g(\frac{n}{P_j},j-1)\)中多減去了\(\sum_{i=1}^{j-1}f(P_i)\)這些最小質因子小於\(P_j\)的函數值,所以再把它們加上就好了。

所以總結起來就是:

\[g(n,j)=\begin{cases} g(n,j-1)&P_j^2\gt n\\ g(n,j-1)-f(P_j)[g(\frac{n}{P_j},j-1)-\sum_{i=1}^{j-1}f(P_i)]&P_j^2\le n\end{cases} \]

關於\(g(n,j)\)的初值問題:\(g(n,0)\)表示所有數的和,也就是把所有數都當作是質數帶入\(f(p)\)的那個多項式中算出的結果。

因為最后只要求所有的\(g(x,|P|)\),所以在求的時候數組只開了一維。這樣做的復雜度被證明是\(O(\frac{n^{\frac 34}}{\log n})\)的。

\(f(x)=1\)即求\(n\)以內的質數個數為例:

for (int i=1,j;i<=n;i=j+1){
	j=n/(n/i);w[++m]=n/i;
	if (w[m]<=Sqr) id1[w[m]]=m;
	else id2[n/w[m]]=m;
	g[m]=(w[m]-1)%mod;
}
for (int j=1;j<=tot;++j)
	for (int i=1;i<=m&&pri[j]*pri[j]<=w[i];++i){
		int k=(w[i]/pri[j]<=Sqr)?id1[w[i]/pri[j]]:id2[n/(w[i]/pri[j])];
		g[i]=(g[i]-g[k]+j-1)%mod;g[i]=(g[i]+mod)%mod;
	}

說了那么多你求出了啥?

現在我們已經對於\(x=\lfloor\frac ni\rfloor\)求出了\(\sum_{i=1}^x[i是質數]f(i)\)

我們設\(S(n,j)=\sum_{i=1}^n[\min(p)\ge P_j]f(i)\),也就是所有滿足最小質因子大於等於\(P_j\)\(f\)值之和。

那么最終的答案就是\(S(n,1)+f(1)\)

鑒於質數的答案我們已經算出來了,是\(g(n,j)-\sum_{i=1}^{j-1}f(P_i)\)。(因為要保證最小質因子大於等於\(P_j\)所以要把小於它的質數減掉)

考慮合數。我們枚舉這個合數的最小質因子及其出現次數,然后直接乘即可。

\[S(n,j)=g(n,|P|)-\sum_{i=1}^{j-1}f(P_i)+\sum_{k=j}^{P_k^2\le n}\sum_{e=1}^{P_k^{e+1}\le n}S(\frac{n}{P_k^e},k+1)\times f(P_k^e)+f(P_k^{e+1}) \]

然后這個的復雜度也被證明是\(O(\frac{n^{\frac 34}}{\log n})\)的。

舉個栗子

loj6053簡單的函數

定義積性函數\(f(p^c)=p\oplus c\),求其前\(n\)項和。

會發現除了\(2\)以外的質數都滿足\(f(p)=p\oplus 1=p-1\),所以可以分別計算出\(g(x,|P|)=\sum_{i=1}^x[i是質數]i\)以及\(h(x,|P|)=\sum_{i=1}^x[i是質數]1\)

在處理\(S\)的時候,如果\(j=1\),就說明其中包含\(2\)這個因數,因此把答案\(+2\)即可。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define ll long long
const int N = 1e6+5;
const int mod = 1e9+7;
int Sqr,zhi[N],pri[N],sp[N],tot,m,id1[N],id2[N],g[N],h[N];
ll n,w[N];
void Sieve(int n){
	zhi[1]=1;
	for (int i=2;i<=n;++i){
		if (!zhi[i]) pri[++tot]=i,sp[tot]=(sp[tot-1]+i)%mod;
		for (int j=1;i*pri[j]<=n;++j){
			zhi[i*pri[j]]=1;
			if (i%pri[j]==0) break;
		}
	}
}
int S(ll x,int y){
	if (x<=1||pri[y]>x) return 0;
	int k=(x<=Sqr)?id1[x]:id2[n/x];
	int res=(1ll*g[k]-h[k]-sp[y-1]+y-1)%mod;res=(res+mod)%mod;
	if (y==1) res+=2;
	for (int i=y;i<=tot&&1ll*pri[i]*pri[i]<=x;++i){
		ll p1=pri[i],p2=1ll*pri[i]*pri[i];
		for (int e=1;p2<=x;++e,p1=p2,p2*=pri[i])
			(res+=(1ll*S(x/p1,i+1)*(pri[i]^e)%mod+(pri[i]^(e+1)))%mod)%=mod;
	}
	return res;
}
int main(){
	scanf("%lld",&n);
	Sqr=sqrt(n);Sieve(Sqr);
	for (ll i=1,j;i<=n;i=j+1){
		j=n/(n/i);w[++m]=n/i;
		if (w[m]<=Sqr) id1[w[m]]=m;
		else id2[n/w[m]]=m;
		h[m]=(w[m]-1)%mod;
		g[m]=((w[m]+2)%mod)*((w[m]-1)%mod)%mod;
		if (g[m]&1) g[m]+=mod;g[m]/=2;
	}
	for (int j=1;j<=tot;++j)
		for (int i=1;i<=m&&1ll*pri[j]*pri[j]<=w[i];++i){
			int k=(w[i]/pri[j]<=Sqr)?id1[w[i]/pri[j]]:id2[n/(w[i]/pri[j])];
			g[i]=(g[i]-1ll*pri[j]*(g[k]-sp[j-1])%mod)%mod;g[i]=(g[i]+mod)%mod;
			h[i]=(h[i]-h[k]+j-1)%mod;h[i]=(h[i]+mod)%mod;
		}
	printf("%d\n",S(n,1)+1);
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM