Min_25 筛

Min_25 筛 2020.9.24

这阅读量都14k了就离谱。

本来打算把之前的内容删了重写的,纠结了一下还是决定保留下来,大家就当看了图个乐。

Min_25筛是干啥的

O(n0.75logn)求积性函数前缀和。

咋做啊

大致分两步:

  • 对所有x=nd筛出不超过x的所有质数的f值之和
  • 求解原问题,即所有x=nd筛出不超过x的所有数的f值之和

为了方便,我们定义g(i)(iN)表示把i当成质数计算f(i)得到的结果。

定义prij表示第j小的质数,sumj=k=1jf(prik)=k=1jg(prik)

(因为一个合数的最小质因子小于其开根号,因此预处理质数时只需要考虑n的质数,记tot表示这部分质数的数量。)

Min_25筛对被求解的积性函数f有一定的要求,最重要的一点是当给出iSg(i)时,能够快速的计算出iSg(i×prij)

第一步

我们记G(i,j)(i=nd)表示i以内所有质数以及最小质因子>prij的合数的g之和。

初始时G(i,0)=k=2ig(k)

从小到大枚举质因子prij,把最小质因子恰好为prij的那些合数的gG中去掉。枚举prij2的所有iG(i,j)需要去掉的部分是G(iprij,j1)sumj1并把g(i)变成g(i×prij)

最终求出G(i,tot)就是i以内所有质数的f之和。

第二步

我们记F(i,j)(i=nd)表示i以内所有质数以及最小质因子>prij的合数的f之和。

初始时F(i,tot)=G(i,tot)

从大到小枚举prij,把最小质因子恰好为prij的那些合数的f加到F中去。枚举prij2的所有i,再额外枚举prije+1i的指数e,把F(iprije,j)×f(prije)+f(prije+1)加进F(i,j1)

最后F(i,0)就是答案了!!1

时间复杂度

要是写得不对的话可以来喷我。

对于一个数x,满足p2x的质数p的数量是O(xlogx)

考虑第一步的复杂度。考虑每个i=nd被多少个质数枚举到了,有

T(n)=x=1nO(xlogx)+x=1nO(n/xlogn/x)

log都是同级的可以提出来(?)

x=1nO(x)+x=1nO(n/x)0nxdx+0nn/xdx=23n34+2n34=O(n0.75)

所以总复杂度就是O(n0.75logn)了(迫真)


以下是原来写的。

yyb好神仙啊

干什么用的

可以在O(n34logn)的时间内求积性函数f(x)的前缀和。

别问我为什么是这个复杂度

要求f(p)是一个关于p的简单多项式,f(pc)可以快速计算。

怎么做啊

首先我们需要对每个x=ni求出i=1x[i]f(i)

怎么求呢?

先线性筛出n范围内的质数,设Pj表示从小到大第j个质数。

g(n,j)=i=1n[iP or min(p)>Pj]f(i)

说人话就是:i是质数,或者i的最小质因子大于Pj,把1n内满足条件的f(i)加起来就是g(n,j)

这个东西的实际含义是什么呢?可以参考一下埃氏筛法的运行过程。

假设现在有n个数依次排开,第i个数是f(i),根据埃氏筛法的那套理论,每次选出一个质数,然后筛掉它的所有倍数。

会发现g(n,j)就是运行j次埃氏筛法后,没被筛掉的所有数之和加上所有的f(p)

我们要求的i=1x[i]f(i)其实就是g(x,|P|),其中|P|是质数集合的大小。

考虑g(n,j)的转移,分两种情况:

1、Pj2>n。此时运行的第j次已经不会再筛掉任何数了(因为第j次运行中筛掉的最小的数是Pj2),所以此时g(n,j)=g(n,j1)

2、Pj2n。这时候我们就要考虑哪些数被筛掉了。被筛掉的数一定含有质因子Pj,且除掉Pj后最小的质因子会大于等于Pj。考虑减去f(Pj)×g(nPj,j1),但在g(nPj,j1)中多减去了i=1j1f(Pi)这些最小质因子小于Pj的函数值,所以再把它们加上就好了。

所以总结起来就是:

g(n,j)={g(n,j1)Pj2>ng(n,j1)f(Pj)[g(nPj,j1)i=1j1f(Pi)]Pj2n

关于g(n,j)的初值问题:g(n,0)表示所有数的和,也就是把所有数都当作是质数带入f(p)的那个多项式中算出的结果。

因为最后只要求所有的g(x,|P|),所以在求的时候数组只开了一维。这样做的复杂度被证明是O(n34logn)的。

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=ni求出了i=1x[i]f(i)

我们设S(n,j)=i=1n[min(p)Pj]f(i),也就是所有满足最小质因子大于等于Pjf值之和。

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

鉴于质数的答案我们已经算出来了,是g(n,j)i=1j1f(Pi)。(因为要保证最小质因子大于等于Pj所以要把小于它的质数减掉)

考虑合数。我们枚举这个合数的最小质因子及其出现次数,然后直接乘即可。

S(n,j)=g(n,j)i=1j1f(Pi)+k=jPk2ne=1Pke+1nS(nPke,k+1)×f(Pke)+f(Pke+1)

然后这个的复杂度也被证明是O(n34logn)的。

举个栗子

loj6053简单的函数

定义积性函数f(pc)=pc,求其前n项和。

会发现除了2以外的质数都满足f(p)=p1=p1,所以可以分别计算出g(x,|P|)=i=1x[i]i以及h(x,|P|)=i=1x[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;
}

posted @   租酥雨  阅读(23554)  评论(11编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示