min25筛学习笔记&模板详解

min25筛算法推导&模板详解

问题引入

引入函数 σ 0 ( n ) \sigma _0(n) σ0(n)为n的正因数的数量,求 S ( n , k ) = ∑ i = 1 n σ 0 ( i k ) S(n,k)=\sum_{i=1}^n\sigma_0(i^k) S(n,k)=i=1nσ0(ik), n , k ≤ 1 0 10 n,k\le 10^{10} n,k1010

简化分析与引入

对于 σ 0 ( n ) \sigma_0(n) σ0(n)函数,显然有:
当 p 为 素 数 , n 为 p k   σ 0 ( n ) = k + 1 当p为素数,n为p^k\ \sigma_0(n)=k+1\\ pnpk σ0(n)=k+1
且显然 σ 0 \sigma_0 σ0为积性函数

n ≤ 1 0 7 n\le 10^7 n107时可以通过

#include<bits/stdc++.h> 
const int size=1e7+5;
bool prime[size];
int p[size];
int sigma[size];
int tot=0;
int k;
void init()
{
	sigma[1]=1;
    for(int i=2;i<size;i++) prime[i]=true;
    for(int i=2;i<size;i++)
    {
        if(prime[i]) 
        {
            p[tot++]=i;
            sigma[i]=k+1;
        }
        for(int j=0;j<tot&&p[j]*i<size;j++)
        {
            prime[i*p[j]]=false;
            if(i%p[j]==0)
            {
                sigma[i*p[j]]=sigma[i]*2-sigma[i/p[j]];
                break;
            }
            else 
            {
                sigma[i*p[j]]=sigma[i]*(k+1);
            }
        }
    }
}
int main()
{
	int n;
	scanf("%d%d",&n,&k);
	init();
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		ans+=sigma[i];
	}
	printf("%d\n",ans);
}

这样对于每个n,k我们都可以线性求解出答案。但是当n最大可以达到 1 0 10 10^{10} 1010时,这种做法显然是不行的为此就需要引入一种亚线性筛:“min25筛”

虽然min25筛乃至杜教筛名字上都带有一个筛字但是实际上并不能称作一种筛,准确地说,其应该是一种可以亚线性地复杂度下求出积性函数前缀和的算法。其中min25筛求解积性函数前缀和时需要满足条件

  • f ( x ) f(x) f(x)当x为质数时有一个多项式表示
  • f ( x c ) f(x^c) f(xc)在x为质数时可以快速计算

这两条条件都将在下面的推导种起到重要的作用。

前置知识

埃拉托斯特尼筛法

在线性求解一些数论问题时常常需要用到线性筛,但是有事也可以使用复杂度稍差一点,但是依然有效的埃拉托斯特尼筛法(下面简称埃氏筛法)。其主要的想法是每筛出来一个素数,就将其倍数也删去,这样不断向前递推,未被筛去的就是素数

bool prime[N];
void init(){
    for(int i=2;i<N;i++) prime[i]=true;
    for(int i=2;i<N;i++){
        if(prime[i]){
            for(int j=2*i;j<N;j+=i){
                prime[j]=false;
            }
        }
    }
}

当然,min25筛其实并不用到埃氏筛,但是其借鉴了一点埃氏筛的思想

引理1

对于给定的正整数n和所有的正整数, ⌊ n m ⌋ \lfloor\frac{n}{m}\rfloor mn的取值只有 O ( n ) O(\sqrt{n}) O(n )

证明. 当 m ≤ n ​ m\le \sqrt n​ mn 时满足条件的m只有 O ( n ) ​ O(\sqrt{n})​ O(n )种。当 m &gt; n ​ m&gt;\sqrt n​ m>n 时, 0 ≤ ⌊ n m ⌋ &lt; n ​ 0\le \lfloor\frac{n}{m}\rfloor&lt;\sqrt n​ 0mn<n 满足这一条件的 ⌊ n m ⌋ ​ \lfloor\frac{n}{m}\rfloor​ mn也只有 O ( n ) ​ O(\sqrt{n})​ O(n )种,故得证

min25筛的分析与推导

我们将问题泛化,令 f ( x ) = σ 0 ( x k ) f(x)=\sigma_0(x^k) f(x)=σ0(xk),由于 σ 0 ( x ) \sigma_0(x) σ0(x)函数为积性函数,易证*f(x)*也为积性函数。且因为 f ( x c ) = c ∗ k + 1 f(x^c)=c*k+1 f(xc)=ck+1,因此积性函数 f ( x ) f(x) f(x)满足上面所提到的min25筛求解积性函数前缀和的条件。现要求积性函数 f ( x ) ​ f(x)​ f(x)的前缀和。

为了方便公式的书写,我们需要先引入一些定义
P : 素 数 集 合 l p f ( n ) : n 的 最 小 质 因 数 P i : 埃 氏 筛 法 筛 了 前 i 个 质 数 之 后 剩 下 的 自 然 数 集 合 p i : 第 i 个 质 数 P:素数集合\\ lpf(n):n的最小质因数\\ P_i:埃氏筛法筛了前i个质数之后剩下的自然数集合\\ p_i:第i个质数 P:lpf(n):nPi:ipi:i

将原前缀和的求和方式进行转化
∑ i = 1 n f ( i ) = 1 + ∑ 2 ≤ p ≤ n &ThinSpace; p ∈ P ∑ 2 ≤ x ≤ n &ThinSpace; l p f ( x ) = p f ( x ) \sum_{i=1}^nf(i)=1+\sum_{2\le p\le n\,p\in P}\sum_{2\le x\le n\,lpf(x)=p}f(x) i=1nf(i)=1+2pnpP2xnlpf(x)=pf(x)
由于*f(x)*为积性函数,故
1 + ∑ 2 ≤ p ≤ n &ThinSpace; p ∈ P ∑ 2 ≤ x ≤ n &ThinSpace; l p f ( x ) = p f ( x ) = 1 + ∑ 2 ≤ p e ≤ n , e ≥ 1 , p ∈ P f ( p e ) ( 1 + ∑ 2 ≤ x ≤ ⌊ n p e ⌋ , l p f ( x ) &gt; p f ( x ) ) 1+\sum_{2\le p\le n\,p\in P}\sum_{2\le x\le n\,lpf(x)=p}f(x)=1+\sum_{2\le p^e\le n,e\ge1,p\in P}f(p^e)\left(1+\sum_{2\le x\le \lfloor\frac{n}{p^e}\rfloor,lpf(x)&gt;p}f(x)\right) 1+2pnpP2xnlpf(x)=pf(x)=1+2pen,e1,pPf(pe)1+2xpen,lpf(x)>pf(x)
显然,对于一个合数来说,其最小的质数定然不会超过 n \sqrt{n} n ,因此上式就可以进行进一步的转化
∑ i = 1 n f ( i ) = 1 + ∑ 2 ≤ p ≤ n &ThinSpace; p ∈ P ∑ 2 ≤ x ≤ n &ThinSpace; l p f ( x ) = p f ( x ) = 1 + ∑ 2 ≤ p e ≤ n , e ≥ 1 , p ∈ P f ( p e ) ( 1 + ∑ 2 ≤ x ≤ ⌊ n p e ⌋ , l p f ( x ) &gt; p f ( x ) ) = 1 + ∑ 2 ≤ p ≤ n 2 ≤ p e ≤ n , e ≥ 1 , p ∈ P f ( p e ) ( 1 + ∑ 2 ≤ x ≤ ⌊ n p e ⌋ , l p f ( x ) &gt; p f ( x ) ) + ∑ n &lt; p ≤ n , p ∈ P f ( p ) \begin{aligned} \sum_{i=1}^nf(i)&amp;=1+\sum_{2\le p\le n\,p\in P}\sum_{2\le x\le n\,lpf(x)=p}f(x)\\ &amp;=1+\sum_{2\le p^e\le n,e\ge1,p\in P}f(p^e)\left(1+\sum_{2\le x\le \lfloor\frac{n}{p^e}\rfloor,lpf(x)&gt;p}f(x)\right)\\&amp;=1+\sum_{2\le p\le \sqrt{n}2\le p^e\le n,e\ge1,p\in P }f(p^e)\left(1+\sum_{2\le x\le \lfloor\frac{n}{p^e}\rfloor,lpf(x)&gt;p}f(x)\right)+\sum_{\sqrt{n}&lt;p\le n,p\in P}f(p) \end{aligned} i=1nf(i)=1+2pnpP2xnlpf(x)=pf(x)=1+2pen,e1,pPf(pe)1+2xpen,lpf(x)>pf(x)=1+2pn 2pen,e1,pPf(pe)1+2xpen,lpf(x)>pf(x)+n <pn,pPf(p)
但是直接求这个有一定的难度,为此引入两个新的函数
g ( n , m ) = ∑ 2 ≤ x ≤ n , l p f ( x ) &gt; m f ( x ) h ( n ) = ∑ 2 ≤ p ≤ n , p ∈ P f ( p ) g(n,m)=\sum_{2\le x\le n,lpf(x)&gt;m}f(x)\\ h(n)=\sum_{2\le p\le n,p\in P} f(p) g(n,m)=2xn,lpf(x)>mf(x)h(n)=2pn,pPf(p)
原式即是 g ( n , 0 ) g(n,0) g(n,0)

为此我们对g(n,m)进行推导
g ( n , m ) = ∑ 2 ≤ x ≤ n , l p f ( x ) &gt; m f ( x ) = ∑ m &lt; p ≤ n , p e ≤ n , e ≥ 1 , p ∈ P f ( p e ) ( 1 + ∑ 2 ≤ x ≤ ⌊ n p e ⌋ , l p f ( x ) &gt; p f ( x ) ) + ∑ n &lt; p ≤ n , p ∈ P f ( p ) = ∑ m &lt; p ≤ n , p e ≤ n , e ≥ 1 , p ∈ P f ( p e ) ( 1 + g ( ⌊ n p e , p ⌋ ) ) + h ( n ) − h ( n ) \begin{aligned} g(n,m)&amp;=\sum_{2\le x\le n,lpf(x)&gt;m}f(x)\\ &amp;=\sum_{m&lt;p\le \sqrt{n},p^e\le n,e\ge1,p\in P}f(p^e)\left(1+\sum_{2\le x\le \lfloor\frac{n}{p^e}\rfloor,lpf(x)&gt; p}f(x)\right)+\sum_{\sqrt{n}&lt;p\le n,p\in P}f(p)\\ &amp;=\sum_{m&lt;p\le \sqrt{n},p^e\le n,e\ge1,p\in P}f(p^e)\left(1+g(\lfloor\frac{n}{p^e},p\rfloor)\right)+h(n)-h(\sqrt{n}) \end{aligned} g(n,m)=2xn,lpf(x)>mf(x)=m<pn ,pen,e1,pPf(pe)1+2xpen,lpf(x)>pf(x)+n <pn,pPf(p)=m<pn ,pen,e1,pPf(pe)(1+g(pen,p))+h(n)h(n )
但是这样不便于式子之间的转化,因此将原式中的素数部分的函数值的递推转化一下
g ( n , m ) = ∑ m &lt; p ≤ n , p e ≤ n , e ≥ 1 , p ∈ P f ( p e ) ( [ e &gt; 1 ] + g ( ⌊ n p e , p ⌋ ) ) + ∑ m &lt; p ≤ n , p ∈ P f ( x ) + h ( n ) − h ( n ) = ∑ m &lt; p ≤ n , p e ≤ n , e ≥ 1 , p ∈ P f ( p e ) ( [ e &gt; 1 ] + g ( ⌊ n p e , p ⌋ ) ) + h ( n ) − h ( m ) \begin{aligned} g(n,m)&amp;=\sum_{m&lt;p\le \sqrt{n},p^e\le n,e\ge1,p\in P}f(p^e)\left([e&gt;1]+g(\lfloor\frac{n}{p^e},p\rfloor)\right)+\sum_{m&lt;p\le \sqrt{n},p\in P}f(x)+h(n)-h(\sqrt{n})\\ &amp;=\sum_{m&lt;p\le \sqrt{n},p^e\le n,e\ge1,p\in P}f(p^e)\left([e&gt;1]+g(\lfloor\frac{n}{p^e},p\rfloor)\right)+h(n)-h(m) \end{aligned} g(n,m)=m<pn ,pen,e1,pPf(pe)([e>1]+g(pen,p))+m<pn ,pPf(x)+h(n)h(n )=m<pn ,pen,e1,pPf(pe)([e>1]+g(pen,p))+h(n)h(m)
对于我们想要得到的 g ( n , 0 ) g(n,0) g(n,0)我们需要枚举所有的小于等于 n \sqrt{n} n 的素数作为m并将其对应的 g ( n , m ) g(n,m) g(n,m)加上才可以最后得到答案。需要注意的是当 n ≤ m 2 n\le m^2 nm2时, g ( n , m ) = 0 g(n,m)=0 g(n,m)=0这是显然可以得知的,当 n ≤ m 2 n\le m^2 nm2时,1到n之间,不存在最小质因数还大于m的数字。

由于前面的条件 f ( p e ) f(p^e) f(pe)是可以快速计算的,因此接下来只要预处理出h就可以进行递推了。

接下来考虑如何求 h h h

首先可以发现所有需要用到的h的标号均为0到 n ​ \sqrt{n}​ n 之间的质数,或为 ⌊ n p e ⌋ ​ \lfloor\frac{n}{p^e}\rfloor​ pen

现在证明:对于所有需要用到的 h ( i ) h(i) h(i)其一定满足,存在m使得 ⌊ n m ⌋ = i \lfloor\frac{n}{m}\rfloor=i mn=i

证 : 令 ⌊ n p ⌋ = k , p 为 任 意 的 小 于 等 于 n 的 数 则 有 n = p ∗ k + b ( b &lt; p ) n ÷ k = p … … b ∵ p ≤ n ∴ k ≥ n ∴ k &gt; b ∴ ⌊ n k ⌋ = p \begin{aligned} 证:&amp;令\lfloor\frac{n}{p}\rfloor=k,p为任意的小于等于n的数\\ &amp;则有n=p*k+b(b&lt;p)\\ &amp;n\div k=p……b\\ &amp;\because p\le\sqrt{n}\\ &amp;\therefore k\ge\sqrt{n}\\ &amp;\therefore k&gt;b\\ &amp;\therefore\lfloor\frac{n}{k}\rfloor=p\\ \end{aligned} pn=kpnn=pk+b(b<p)n÷k=pbpn kn k>bkn=p
由此得出,所有小于等于 n \sqrt{n} n 的数字都是满足上述的可以通过 ⌊ n m ⌋ \lfloor\frac{n}{m}\rfloor mn得到的,而所有0到 n \sqrt{n} n 之间的数字自然也就满足这个条件,而 ⌊ n p e ⌋ \lfloor\frac{n}{p^e}\rfloor pen则是也显然满足这个条件,因此得证

根据引理1,满足这种条件的数字共有 O ( n ) O(\sqrt n) O(n )个.由于h函数是对f函数求素数前缀和,且上面说到了,所有满足可以用min25筛求的积性函数都需要满足 f ( p ) f(p) f(p)可以通过多项式表示,也即f函数可以表示为 f ( p ) = ∑ a t p b t f(p)=\sum a_tp^{b_t} f(p)=atpbt,不妨令 f t ( p ) = a t p b t f_t(p)=a_tp^{b_t} ft(p)=atpbt, f t f_t ft函数的前缀和为 h t ( i ) h_t(i) ht(i)因此h函数也就可以表示为 h ( i ) = ∑ t h t ( i ) h(i)=\sum_{t}h_t(i) h(i)=tht(i)。进而,对于每个h(i)我们只需要求出所有的 h t ( i ) h_t(i) ht(i)即可。

到了这里我们的问题就变成了:给定n和t,对所有满足 i = ⌊ n m ⌋ i=\lfloor\frac{n}{m}\rfloor i=mn,求:
h t ( i ) = ∑ p ≤ i , p ∈ P p b t h_t(i)=\sum_{p\le i,p\in P}p^{b_t} ht(i)=pi,pPpbt
为了求这个函数我们需要引入一个新的函数 h t , i ′ ( j ) h&#x27;_{t,i}(j) ht,i(j),其含义为埃氏筛法筛出前i个数之后,前j个数字种剩余的数字的 b t b_t bt次方和
h t , i ′ ( j ) = ∑ 1 ≤ p ≤ j p = 1   o r   p ∈ P   o r   l p f ( p ) &gt; p i p b t h&#x27;_{t,i}(j)=\sum_{1\le p \le j\\p=1\ or\ p\in P\ or\ lpf(p)&gt;p_i}p^{b_t} ht,i(j)=1pjp=1 or pP or lpf(p)>pipbt
那么函数 h t ( j ) = h t , i ( j ) ( j &lt; p i + 1 ∗ p i + 1 ) h_t(j)=h_{t,i}(j)(j&lt;p_{i+1}*p_{i+1}) ht(j)=ht,i(j)(j<pi+1pi+1)

对于 h t , i ′ ( j ) h&#x27;_{t,i}(j) ht,i(j)有转移式
h t , i ( j ) = h t , 0 ′ ( j ) − ∑ k = 0 k &lt; i p k + 1 b t ( h t , k ′ ( ⌊ j p k + 1 ⌋ ) − h t , k ′ ( p k ) ) h_{t,i}(j)=h&#x27;_{t,0}(j)-\sum_{k=0}^{k&lt;i}p_{k+1}^{b_t}(h&#x27;_{t,k}(\lfloor\frac{j}{p_{k+1}}\rfloor)-h&#x27;_{t,k}(p_k)) ht,i(j)=ht,0(j)k=0k<ipk+1bt(ht,k(pk+1j)ht,k(pk))
由此,h函数的求值就结束了。

由此就可以得到积性函数f的前缀和了。上述算法的复杂度为 O ( n 3 4 l o g ( n ) ) O(\frac{n^{\frac{3}{4}}}{log(n)}) O(log(n)n43),现在还有一种新版的min25筛可以优化到 O ( n 2 3 ) O(n^{\frac{2}{3}}) O(n32)但是实际应用上,由于常数巨大,实际上的运行时间并不优化多少,且代码冗长,故此处不予介绍。

模板及解释

//问题描述定义:
//定义sigma(n)为n的正因数的数量,求f(n,k)=sum_{i=1}^n (sigma(i^k))
#include<stdio.h>
#include<math.h>

using namespace std;
typedef unsigned long long ull;
typedef long long ll;

const int N=200005;

int T,S,pr[N],pc;
ll n,num[N],m,K;
ull g[N];
bool fl[N];
// 给定一个数字X求出其为第几个可以得到有效的g的数字
inline int ID(ll x){return x<=S?x:m-n/x+1;}

ull f(ll n,int i){
    if(n<1||pr[i]>n)return 0;
    ull ret=g[ID(n)]-(i-1)*(K+1);
    while((ll)pr[i]*pr[i]<=n){
        int p=pr[i];
        ull e=K+1,t=n/p;
        while(t>=p)ret+=f(t,i+1)*e+e+K,t/=p,e+=K;
        // ret= sum{sigma(p^es)([n>1]+f(n/p^es,p)+g[n]-g[num[i-1]]}
        // 因为对于函数g(n,m)当n<=m^2,g(n,m)为0
        // 且根据sigma函数的性质,对于质数p,有sigma(p^es)=es*k+1
        // 所以 ret+=(es*k+1)*f(n/p^es,p)+((es+1)k+1)(1<=es&& n/p^es>p)即当前项的sigma(p^e)*f(n/p^e,p)加上下一项的sigma(p^e)
        // 这样的做法避免了e<1也就不必进行特判
        i++;
    }
    return ret;
}
//g[i]即小于i的所有质数的sigma函数求和
//根绝前面的推导,只有当i可以通过[n/m]得到时,其才有用
ull solve(ll n){
    int i,p,x;ull y;
    S=sqrt(n);
    while((ll)S*S<=n)S++;
    while((ll)S*S>n)S--;
    while(m)num[m--]=0;
    for(i=1;i<=S;i++)num[++m]=i;
    for(i=S;i>=1;i--)if(n/i>S)num[++m]=n/i;
    for(i=1;i<=m;i++)g[i]=num[i]-1;
    //此处g[i]为小于等于第i个满足可以通过[n/m]得到的数的素因子的数量
    //故先减去“1”因为1一定不为素因子且无法被后续操作筛去
    x=1;y=0;
    for(p=2;p<=S;p++)if(g[p]!=g[p-1]){
        while(num[x]<(ll)p*p)x++;
        //令g'(i,j)为埃氏筛法筛出前j个素数后,1到j之间剩余数的数量
        //则有g'(i,j)=g'(0,j)-sum_{k=0,k<i}(g'(k,[j/p[k+1]])-g'(k,p[k]))
        //其中p[0]=1,p[i](i>0)为第i个质数
        //则g(j)即为g'(i,j)使得有p[i]<j&&p[i+1]>j
        //其中g'(k,p[k])即为k+1
        //由于以上的递推式仅仅作用到num[x]>=p^2为止,故仅仅将更新到x
        //由于每次都要减去尚未去除当前素数的g以充当g'因此从大往小更新
        for(i=m;i>=x;i--)g[i]-=g[ID(num[i]/p)]-y;
        y++;
    }
    for(i=1;i<=m;i++)g[i]*=K+1;
    return f(n,1)+1;
}

int main(){
    int i,j;
    //素数筛
    for(i=2;i<N;i++)if(!fl[i]){
        pr[++pc]=i;
        for(j=i+i;j<N;j+=i)fl[j]=1;
    }
    for(scanf("%d",&T);T--;){
        scanf("%lld%lld",&n,&K);
        printf("%llu\n",solve(n));
    }
    return 0;
}

参考资料

  1. 朱震霆的国家集训队论文: 《一些特殊的数论函数求和问题》, 国家集训队2018论文集
  2. 新版min25筛(O(n^(2/3)))详解 https://zhuanlan.zhihu.com/p/60378354
  3. yyb的博客 https://www.cnblogs.com/cjyyb/p/9185093.html
  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值