• Min_25 筛


    Min_25 筛 2020.9.24

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

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

    Min_25筛是干啥的

    (O(frac{n^{0.75}}{log n}))求积性函数前缀和。

    咋做啊

    大致分两步:

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

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

    定义(pri_j)表示第(j)小的质数,(sum_j=sum_{k=1}^{j}f(pri_k)=sum_{k=1}^jg(pri_k))

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

    Min_25筛对被求解的积性函数(f)有一定的要求,最重要的一点是当给出(sum_{i in S}g(i))时,能够快速的计算出(sum_{i in S}g(i imes pri_j))

    第一步

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

    初始时(G(i,0)=sum_{k=2}^{i}g(k))

    从小到大枚举质因子(pri_j),把最小质因子恰好为(pri_j)的那些合数的(g)(G)中去掉。枚举(ge pri_j^2)的所有(i)(G(i,j))需要去掉的部分是(G(lfloorfrac{i}{pri_j} floor,j-1)-sum_{j-1})并把(sum g(i))变成(sum_{g(i imes pri_j)})

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

    第二步

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

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

    从大到小枚举(pri_j),把最小质因子恰好为(pri_j)的那些合数的(f)加到(F)中去。枚举(ge pri_j^2)的所有(i),再额外枚举(pri_j^{e+1}le i)的指数(e),把(F(lfloorfrac{i}{pri_j^e} floor,j) imes f(pri_j^e)+f(pri_j^{e+1}))加进(F(i,j-1))

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

    时间复杂度

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

    对于一个数(x),满足(p^2 le x)的质数(p)的数量是(O(frac{sqrt x}{log sqrt x}))

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

    [T(n)=sum_{x=1}^sqrt{n}O(frac{sqrt x}{log sqrt x})+sum_{x=1}^{sqrt n}O(frac{sqrt {n/x}}{log sqrt {n/x}}) ]

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

    [sum_{x=1}^sqrt{n}O(sqrt x)+sum_{x=1}^{sqrt n}O(sqrt {n/x})\approxint_{0}^{sqrt n}sqrt xdx+int_{0}^{sqrt n}sqrt{n/x}dx\=frac{2}{3}n^{frac{3}{4}}+2n^{frac{3}{4}}\=O(n^{0.75}) ]

    所以总复杂度就是(O(frac{n^{0.75}}{log n}))了(迫真)


    以下是原来写的。

    yyb好神仙啊

    干什么用的

    可以在(O(frac{n^{frac 34}}{log n}))的时间内求积性函数(f(x))的前缀和。

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

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

    怎么做啊

    首先我们需要对每个(x=lfloorfrac ni floor)求出(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^2le n)。这时候我们就要考虑哪些数被筛掉了。被筛掉的数一定含有质因子(P_j),且除掉(P_j)后最小的质因子会大于等于(P_j)。考虑减去(f(P_j) imes 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)=egin{cases} g(n,j-1)&P_j^2gt 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^2le nend{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=lfloorfrac ni floor)求出了(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,j)-sum_{i=1}^{j-1}f(P_i)+sum_{k=j}^{P_k^2le n}sum_{e=1}^{P_k^{e+1}le n}S(frac{n}{P_k^e},k+1) imes f(P_k^e)+f(P_k^{e+1}) ]

    然后这个的复杂度也被证明是(O(frac{n^{frac 34}}{log n}))的。

    举个栗子

    loj6053简单的函数

    定义积性函数(f(p^c)=poplus c),求其前(n)项和。

    会发现除了(2)以外的质数都满足(f(p)=poplus 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
    ",S(n,1)+1);
    	return 0;
    }
    
    
  • 相关阅读:
    JavaScript初学者应注意的七个细节
    8个高质量图标的最佳搜索引擎
    Adobe CS5 For Mac综合贴(2011/01/22更新)
    http://apps.hi.baidu.com/share/detail/18571966
    不要使用@import
    【leetcode】Search in Rotated Sorted Array
    【leetcode】Excel Sheet Column Title
    C#Tcp多个客户端与服务器数据与文件传输
    唯一分解定理
    欧拉函数
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9187319.html
Copyright © 2020-2023  润新知