Loading

Min25 筛学习笔记

求解 \(s(n)=\sum_{i=1}^nf(i)\)

\(min25\) 筛的想法就是分为质数的贡献,和所有的贡献来计算。

我们首先构造一个函数 \(F\) ,它满足以下条件

  1. 在质数处取值与 \(f\) 相等

  2. 是一个完全积性函数

  3. 能够快速求解前缀和

我们设 \(G(n,i)\) 表示 \(2-n\) 这些数中,所有的质数或者最小质因子大于 \(p_i\) 的数的 \(F\) 之和。

\(G(n,0)\) 开始递推,容易发现\(G(n,0)=\sum_{i=1}^nF(i)\) ,每次转移都是筛去一部分合数。由于 \(G(\left\lfloor \frac{n}{p_i}\right\rfloor ,i-1)\) 中还储存了 \(p_1-p_{i-1}\) 这些数的贡献,而这一部分数与 \(p_i\) 的乘积的最小质因子就不等于 \(p_i\) 的,也就是不应该被筛掉,所以还要额外加上这些数的贡献。故转移方程如下

\[G(n,i) = \begin{cases} G(n,i-1) & p_i^2>n \\ G(n,i-1)-F(P_i)(G(\left\lfloor \frac{n}{p_i}\right\rfloor,i-1)-\sum_{j=1}^{i-1}F(P_j)) & p_i^2\leq n\\ \end{cases} \]

\(p_{Limit}\) 是满足小于等于 \(\sqrt n\) 的最大的一个质数,则不会存在小于等于 \(n\) ,且满足最小质因子大于 \(p_{Limit}\) 的合数。故此时储存的就是所有质数的 \(F\) 之和。

考虑完质数的,我们在来考虑所有的。

\(S(n,i)\) 表示 \(2-n\) 这些数中,最小质因子大于 \(p_i\) 的数的 \(f\) 之和。那么也就是所有满足条件的质数的贡献加上满足条件的合数的贡献,我们直接枚举 \(p_k^e\) ,将所有存在 \(p_k^e\) 这一因子,且不存在 \(p_k^{e+1}\) 这一因子的合数的 \(f\) 加上。当 \(e\neq 1\) 时,\(p_k^e\) 也是一个合数,它的贡献也需要加上。所以 \(S\) 的转移方程如下

\[S(n,i) = \begin{cases} 0 & p_i\geq n \\ \sum_{j=i+1}^{idx}f(p_j)+\sum_{k=i+1}^{idx}\sum_{p_k^e \leq n}f(p_k^e)(S(\left\lfloor \frac{n}{p_k^e} \right\rfloor ,k)+[e\neq 1]) & p_i<n \end{cases} \]

由于我们在求解过程中一直没有算上 \(1\) 的贡献,在最后加上就好了。

点击查看代码
inline void Init(int n) {
    m=sqrt(n)+1; cnt=0;
    for(LL i=1,j,x;i<=n;i=j+1) {
        x=n/i; j=n/x; val[++cnt]=x;
        if(x<=m) id1[x]=cnt;
        else id2[j]=cnt;
        c1[cnt]=x-1; 
        c2[cnt]=1LL*x*(x+1)/2LL-1;
    }
    for(int i=1,o;i<=idx;i++)   
        for(int j=1;j<=cnt && p[i]*p[i]<=val[j];j++) {
            o=ID(val[j]/p[i]);
            c1[j]-=1LL*(c1[o]-(i-1));
            c2[j]-=1LL*p[i]*(c2[o]-sf[i-1]);
        }
}

inline LL Get_phi(LL x,int y) {
    if(p[y]>=x) return 0;
    int o=ID(x);
    LL g,res=(c2[o]-c1[o])-(sf[y]-y);
    for(int k=y+1;k<=idx && 1LL*p[k]*p[k]<=x;k++) {
        g=p[k];
        for(int e=1;g<=x;e++, g*=p[k]) 
            res+=(g/p[k])*(p[k]-1)*(Get_phi(x/g,k)+(e!=1));
    }
    return res;
}

inline LL Get_mu(LL x,int y) {
	if(p[y]>=x) return 0;
	int o=ID(x);
	LL g,res=(0-c1[o])-(0-y);
	for(int k=y+1;k<=idx && 1LL*p[k]*p[k]<=x;k++)
		res-=Get_mu(x/p[k],k);
	return res;
}
posted @ 2022-10-31 21:05  _YangZJ  阅读(33)  评论(0编辑  收藏  举报