min_25筛(积性函数求和)

A:如来神掌!
B:min_25筛~
A:且慢,我投降。

应用

解决一些较为普遍类型的积性函数的求和问题, ∑ i = 1 n f ( i ) \sum_{i=1}^{n}f(i) i=1nf(i)或者 ∑ p ∈ [ 1 , n ] f ( p ) \sum_{p\in[1,n]}f(p) p[1,n]f(p),可以用 m i n _ 25 min\_25 min_25筛的前提是:可以在过程中快速求解 f ( p k ) f(p^k) f(pk)。时间复杂度为 O ( n 3 4 l o g n ) O(\frac{n^{\frac{3}{4}}}{logn}) O(lognn43),一般的题 n n n 1 e 10 1e10 1e10

求解过程

已是最佳观影顺序,从上往下看应该就能看懂了。
下文中的 p p p指质数, p i p_i pi指第 i i i个质数, m i n ( i ) min(i) min(i)代表 i i i的最小质因子, ∣ P ∣ |P| P表示 [ 1 , n ] [1,\sqrt n] [1,n ]内的因子数量。

g ( x , j ) g(x,j) g(x,j)

定义:

定义 g ( x , j ) g(x,j) g(x,j)为: [ 1 , x ] [1,x] [1,x]中的质数的函数值之和,加上最小质因子大于 p j p_j pj的数的函数值之和。后半部分也就是筛掉前面 j j j个素数的因子后的那些合数。

g ( x , j ) = ∑ p ∈ [ 1 , x ] f ( p ) + ∑ i ∈ [ 1 , x ] , m i n ( i ) > p j f ( i ) g(x,j)=\sum_{p\in[1,x]}f(p)+\sum_{i\in[1,x],min(i)>p_j}f(i) g(x,j)=p[1,x]f(p)+i[1,x],min(i)>pjf(i)

使用原因:

我们可以快速求出 f ( p c ) f(p^c) f(pc),但是其他合数我们并不能快速得出,所以先将其它的合数套用 f ( p ) f(p) f(p)的式子,然后再逐步删掉。剩下的就是正确的质数部分了。

理论:

p j 2 > x p_j^2>x pj2>x时,显然合数的部分不会发生变化,所以此时 g ( x , j ) = g ( x , j − 1 ) g(x,j)=g(x,j-1) g(x,j)=g(x,j1)
p j 2 ≤ x p_j^2\leq x pj2x时,我们考虑减去筛掉的合数部分。

显然这些合数,除上一个 p j p_j pj后,省下部分的最小质因子 ≥ p j \geq p_j pj,所以是剩下部分的 ∑ f = g ( x p j , j − 1 ) − ∑ i = 1 j − 1 f ( p i ) \sum_f=g(\frac{x}{p_j},j-1)-\sum_{i=1}^{j-1}f(p_i) f=g(pjx,j1)i=1j1f(pi) g g g里面多包含了小于 p j p_j pj的质数)

所以当 p j 2 ≤ x p_j^2\leq x pj2x时, g ( x , j ) = g ( x , j − 1 ) − f ( p j ) ∗ [ g ( x p j , j − 1 ) − ∑ i = 1 j − 1 f ( p i ) ] g(x,j)=g(x,j-1)-f(p_j)*[g(\frac{x}{p_j},j-1)-\sum_{i=1}^{j-1}f(p_i)] g(x,j)=g(x,j1)f(pj)[g(pjx,j1)i=1j1f(pi)]

j = 0 j=0 j=0时,根据定义, g ( x , 0 ) = ∑ i = 2 x f ( i ) g(x,0)=\sum_{i=2}^xf(i) g(x,0)=i=2xf(i)

运用:

在接下来的运算中,我们需要用到的是 g ( n i , ∣ P ∣ ) g(\frac{n}{i},|P|) g(in,P),我们预处理这个东西。

g ( x , j ) g(x,j) g(x,j)可以从 g ( x , j − 1 ) g(x,j-1) g(x,j1)转移,所以我们可以用滚动数组省去第二维。第一维 O ( n ) O(n) O(n)开不下,但是我们可以类似离散化,先预存储下所有可能的 n i \frac{n}{i} in。( n i ≤ n \frac{n}{i}\leq \sqrt n inn 的一个数组, n i > n \frac{n}{i}> \sqrt n in>n 的另外一个)

如果说你求解的是 ∑ p ∈ [ 1 , n ] f ( p ) \sum_{p\in[1,n]}f(p) p[1,n]f(p),那么恭喜你,结束了,答案就是 g ( n , ∣ P ∣ ) g(n,|P|) g(n,P)


S ( x , j ) S(x,j) S(x,j)

定义:

S ( x , j ) S(x,j) S(x,j)是所有满足最小质因子 ≥ p j \geq p_j pj的函数值之和,最后的答案就是 S ( n , 1 ) + f ( 1 ) S(n,1)+f(1) S(n,1)+f(1)

理论:

指数部分的答案为: g ( x , ∣ P ∣ ) − ∑ i = 1 j − 1 f ( p i ) g(x,|P|)-\sum_{i=1}^{j-1}f(p_i) g(x,P)i=1j1f(pi),来考虑合数的部分。

我们可以枚举这些合数的最小质因子 p i p_i pi,已经它的次数 e e e,然后递归处理除上 p i e p_i^e pie后的部分。

S ( x , j ) = g ( x , ∣ P ∣ ) − ∑ i = 1 j − 1 f ( p i ) + ∑ i ∈ [ 1 , ∣ P ∣ ] p i 2 ≤ x ∑ e = 1 p i e + 1 ≤ x S ( x p i e , i + 1 ) ∗ f ( p i e ) + f ( p k e + 1 ) S(x,j)=g(x,|P|)-\sum_{i=1}^{j-1}f(p_i)+\sum_{i\in[1,|P|]}^{p_i^2\leq x}\sum_{e=1}^{p_i^{e+1}\leq x}S(\dfrac{x}{p_i^e},i+1)*f(p_i^e)+f(p_k^{e+1}) S(x,j)=g(x,P)i=1j1f(pi)+i[1,P]pi2xe=1pie+1xS(piex,i+1)f(pie)+f(pke+1)


例题

original link - https://loj.ac/problem/6053

min_25筛(积性函数求和)_第1张图片
p > 2 p>2 p>2时, f ( p ) = p − 1 f(p)=p-1 f(p)=p1,所以我们分别求 f ( p ) = p f(p)=p f(p)=p f ( p ) = 1 f(p)=1 f(p)=1 g g g函数值,最后带入 S S S求解即可。

只有当 S ( x , 1 ) S(x,1) S(x,1)时才会带上 2 2 2,那个时候加上2即可。

代码:

/*
 *  Author : Jk_Chen
 *    Date : 2019-09-27-11.16.23
 */
#include
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair
#define fi first
#define se second
#define debug(x) cerr<<#x<<" = "<
const LL mod=1e9+7;
const int maxn=2e5+9;
const int inf=0x3f3f3f3f;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
    while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans; return ans;
}
/*_________________________________________________________begin*/

LL Pow(LL a,LL b,LL mod){
    if(a>=mod)a%=mod;
    LL res=1;
    while(b>0){
        if(b&1)res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
/*_________________________________________________________Pow*/

void Add(LL &a,LL b){a=(a%mod+b%mod);while(a>mod)a-=mod; while(a<0)a+=mod;}
LL inv2=Pow(2,mod-2,mod),inv3=Pow(3,mod-2,mod);

bool vis[maxn];
LL pri[maxn],now;
LL sum[maxn];
void init(int n){// 素数筛
    rep(i,2,n){
        if(!vis[i])pri[++now]=i,sum[now]=(sum[now-1]+i)%mod;
        for(int j=1;j<=now&&1ll*pri[j]*i<=n;j++){
            vis[pri[j]*i]=1;
            if(i%pri[j]==0)break;
        }
    }
}

LL n,sqr;
LL val[maxn],idx1[maxn],idx2[maxn],ct;// 离散化

LL g0[maxn],g1[maxn];// g函数值

LL S(LL x,LL j){
    if(x<=1||pri[j]>x)return 0;
    int k = (x<=sqr ? idx1[x] : idx2[n/x]);
    LL res=0;
    Add(res,g1[k]-g0[k]-(sum[j-1]-(j-1)));
    if(j==1)res+=2;
    rep(i,j,now){
        if(pri[i]*pri[i]>x)break;
        LL now=pri[i],nex=pri[i]*pri[i];
        rep(e,1,100){
            if(nex>x)break;
            Add(res,S(x/now,i+1)*(pri[i]^e)%mod+(pri[i]^(e+1)));
            now=nex,nex*=pri[i];
        }
    }
    return res;
}

int main(){
    n=rd();
    sqr=sqrt(1.0*n);
    init(sqr);
        // n/i 进行分段
    for(LL l=1,r;l<=n;l=r+1){
        r=n/(n/l);
        val[++ct]=n/l;
        n/l<=sqr ? idx1[n/l]=ct : idx2[n/(n/l)]=ct;

            // 初始化g(x,0) x=val[ct]
            // f(p)=1 , 1+1+...1
        g0[ct]=val[ct]-1;
            // f(p)=i , 2+3+...val[ct]
        g1[ct]=(2+val[ct])%mod*((val[ct]-1)%mod)%mod*inv2%mod; // 注意1e10*1e10
    }        
    	// 预处理 g(n/x,|P|) |P|=now
    rep(j,1,now){ //g(val[i],j)
        rep(i,1,ct){
            if(pri[j]*pri[j]>val[i])break; // g(x,j)=g(x,j-1)
            int k = // idx(val[i]/Pj)
                val[i]/pri[j]<=sqr ? idx1[val[i]/pri[j]] : idx2[n/(val[i]/pri[j])];
            Add(g0[i],-(g0[k]-(j-1)));
            Add(g1[i],-pri[j]*(g1[k]-sum[j-1])%mod);
        }
    }
    printf("%lld\n",S(n,1)+1);
    return 0;
}



/*_________________________________________________________end*/


references

https://www.mina.moe/archives/12287
https://www.cnblogs.com/zhoushuyu/p/9187319.html

你可能感兴趣的:(数论/数学,知识点,ACM中的数学问题合集)