Min_25筛简介

\(\text{min_25}\)筛是一种处理一类积性函数前缀和的算法。

其中这类函数\(f(x)\)要满足\(\sum_{i=1}^{n}[i\in prime]\cdot f(i)\)可以被\(\sum_{i=1}^{n}[i\in prime]\cdot i^k\)简单表示或者快速计算,其中\(k\)为较小的常数。

时间复杂度好像是\(O(\frac{n^{0.75}}{\log n})\),不过据说被证伪了...也有人说是\(O(n^{1-\epsilon})\),反正可以做\(n=1e10\),貌似跑的比杜教筛快。

空间复杂度\(O(\sqrt{n})\)。

part 1

首先我们要处理的问题是\(\sum_{i=1}^{n}[i\in prime]\cdot f(i)\),由于函数特性转化为了求\(\sum_{i=1}^{n}[i\in prime]\cdot i^k\)。

设\(g(n,i)=\sum_{i=1}^{n}[i\in prime\ or \ t(i)>p_i]\cdot i^k\),其中\(t(x)\)表示\(x\)的最小质因子,\(p_i\)表示第\(i\)个质数。

直观理解就是埃拉托斯特尼筛法进行了\(i\)轮之后\(1\sim n\)剩下的数的\(k\)次方之和。

显然当\(p_i^2>n\)时\(g(n,i)=g(n,i-1)\),下面只考虑\(p_i^2\leqslant n\)。

我们考虑\(g(n,i)\)如何从\(g(*,i-1)\)转移过来,也就是考虑第\(i\)轮筛掉了那些数。

那么可以得到式子:

\[g(n,i)=g(n,i-1)-p_i^k\cdot \left(g(\lfloor\frac{n}{p_i}\rfloor,i-1)-s_{i-1}\right)
\]

其中\(s_i=\sum_{j=1}^{i}p_i^k\)。

解释一下这个式子,我们考虑筛掉了哪些数,然后减掉就好了,筛掉的那些数最小的质因子显然是\(p_i\),而正好\(g(\lfloor\frac{n}{p_i}\rfloor,i-1)\)代表最小质因子\(\geqslant p_i\)的数以及质数,我们把质数减掉,拼起来就是\(1\sim n\)。

那么写在一起就是:

\[g(n,i)=
\begin{cases}
g(n,i-1)&p_i^2>n\\
g(n,i-1)-p_i^k\cdot \left(g(\lfloor\dfrac{n}{p_i}\rfloor,i-1)-s_{i-1}\right)&p_i^2\leqslant n
\end{cases}
\]

根据常识可以知道第一维只有\(2\sqrt n\)个取值,离散化一下然后递推就好了。

注意到这里我们顺便求出了对于每个\(x\),\(\sum_{i=1}^{\lfloor n/x\rfloor}[i\in prime]\cdot i^k\)的值。

part 2

我们想算出\(f\)的前缀和,同样的我们设\(h(n,i)\)如下:

\[h(n,i)=\sum_{j=1}^{n}[t(j)\geqslant p_i]\cdot f(j)
\]

那么\(h(n,1)+f(1)\)就是答案,注意我们\(h\)不会把\(1\)算进去。

首先还是很显然的,当\(p_i>n\)时,\(h(n,i)=0\),同样下面只考虑\(p_i\leqslant n\)的情况。

我们可以通过\(g\)很简单的算出质数的贡献,即:

\[\sum_{j=1}^{n}[j\in prime]\cdot f(j)-\sum_{j=1}^{i-1}f(p_j)
\]

这些都可以预处理。

然后我们考虑暴力地枚举最小的质因子是多少以及用了多少个,即:

\[\sum_{j=i}^{p_j^2\leqslant n}\sum_{k=1}^{p_j^{k+1}\leqslant n}\left(f(p_j^k)\cdot h(\lfloor\frac{n}{p_j^k}\rfloor,j+1)+f(p_j^{k+1})\right)
\]

解释下后面的\(f(p_j^{k+1})\),这是因为\(h\)没有把\(1\)算进去,所以会漏算质数的次幂,直接加上就行了。

综合起来就是:

\[h(n,i)=\begin{cases}
0&p_i>n\\
\sum_{j=1}^{n}[j\in prime]\cdot f(j)-\sum_{j=1}^{i-1}f(p_j)+\sum_{j=i}^{p_j^2\leqslant n}\sum_{k=1}^{p_j^{k+1}\leqslant n}\left(f(p_j^k)\cdot h(\lfloor\frac{n}{p_j^k}\rfloor,j+1)+f(p_j^{k+1})\right)&p_i\leqslant n
\end{cases}
\]

写成这样求和符号好像有点丑...不管它

直接暴力递归算就好了,递推好像还慢些。

code

[LOJ6053] 简单的函数

\(f(p)=p-1\),\(p=2\)的情况特殊处理下就好了。

#include<bits/stdc++.h>
using namespace std; void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
} void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');} #define lf double
#define ll long long #define pii pair<int,int >
#define vec vector<int > #define pb push_back
#define mp make_pair
#define fr first
#define sc second #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++) const int maxn = 1e6+10;
const int inf = 1e9;
const lf eps = 1e-8;
const int mod = 1e9+7;
const int inv2 = 5e8+4; int add(int x,int y) {return x+y>=mod?x+y-mod:x+y;}
int del(int x,int y) {return x-y<0?x-y+mod:x-y;}
int mul(int x,int y) {return 1ll*x*y-1ll*x*y/mod*mod;} ll n,w[maxn];
int b,tot,pri[maxn],vis[maxn],id[maxn],id2[maxn],m,g[maxn],h[maxn],f[maxn],p[maxn]; void sieve() {
for(int i=2;i<=b<<1;i++) {
if(!vis[i]) pri[++tot]=i,p[tot]=add(p[tot-1],pri[tot]);
for(int j=1;j<=tot&&i*pri[j]<=b<<1;j++) {
vis[i*pri[j]]=1;
if(i%pri[j]==0) break;
}
}
} int get_id(ll x) {return x<=b?id[x]:id2[n/x];} void get_g() {
for(ll l=1;l<=n;) {
ll v=n/l,r=n/v;
if(v<=b) id[v]=++m;else id2[n/v]=++m; //利用整除分块来离散化
w[m]=v,v%=mod;g[m]=mul(v+2,mul(v-1,inv2)),h[m]=del(v,1);l=r+1;
}
for(int i=1;pri[i]<b;i++)
for(int j=1;j<=m;j++) {
if(1ll*pri[i]*pri[i]>w[j]) break; //剪枝
g[j]=del(g[j],mul(pri[i],del(g[get_id(w[j]/pri[i])],p[i-1]))); //g函数记录的是\sum [i\in pri] i,其中第二位滚动掉了
h[j]=del(h[j],del(h[get_id(w[j]/pri[i])],i-1)); //h记录的是\sum [i\in pri] 1
}
for(int i=1;i<=m;i++) f[i]=del(g[i],h[i]);
} int calc(ll x,int i) {
if(x<=1||pri[i]>x) return 0;
int res=del(f[get_id(x)],del(p[i-1],i-1));if(i==1) res=add(res,2); //这里处理了f(2)=2+1的情况
for(int j=i;1ll*pri[j]*pri[j]<=x;j++)
for(ll k=1,e=pri[j];e*pri[j]<=x;e*=pri[j],k++)
res=add(res,add(mul(pri[j]^k,calc(x/e,j+1)),pri[j]^(k+1))); //直接暴力算
return res;
} int main() {
scanf("%lld",&n);b=ceil(sqrt(n));
sieve();get_g();write(add(calc(n,1),1)); //注意加 1
return 0;
}

洛谷P5325 【模板】Min_25筛

这和上题也是一样的,注意别爆\(\text{long long}\)。

#include<bits/stdc++.h>
using namespace std; void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
} void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');} #define lf double
#define ll long long #define pii pair<int,int >
#define vec vector<int > #define pb push_back
#define mp make_pair
#define fr first
#define sc second #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++) const int maxn = 1e6+10;
const int inf = 1e9;
const lf eps = 1e-8;
const int mod = 1e9+7;
const int inv2 = 5e8+4;
const int inv6 = 166666668; int add(int x,int y) {return x+y>=mod?x+y-mod:x+y;}
int del(int x,int y) {return x-y<0?x-y+mod:x-y;}
int mul(int x,int y) {return 1ll*x*y-1ll*x*y/mod*mod;} ll n,w[maxn];
int b,tot,pri[maxn],vis[maxn],id[maxn],id2[maxn],m,g[maxn],h[maxn],f[maxn],p[maxn],p2[maxn]; void sieve() {
for(int i=2;i<=b<<1;i++) {
if(!vis[i]) pri[++tot]=i,p[tot]=add(p[tot-1],pri[tot]),p2[tot]=add(p2[tot-1],mul(i,i));
for(int j=1;j<=tot&&i*pri[j]<=b<<1;j++) {
vis[i*pri[j]]=1;
if(i%pri[j]==0) break;
}
}
} int get_id(ll x) {return x<=b?id[x]:id2[n/x];} void get_g() {
for(ll l=1;l<=n;) {
ll v=n/l,r=n/v;
if(v<=b) id[v]=++m;else id2[n/v]=++m;
w[m]=v,v%=mod;
g[m]=del(mul(mul(v,mul(v+1,(2*v+1)%mod)),inv6),1);
h[m]=del(mul(v,mul(v+1,inv2)),1);l=r+1;
}
for(int i=1;pri[i]<b;i++)
for(int j=1;j<=m;j++) {
if(1ll*pri[i]*pri[i]>w[j]) break;
g[j]=del(g[j],mul(mul(pri[i],pri[i]),del(g[get_id(w[j]/pri[i])],p2[i-1]))); //sum of square of prime
h[j]=del(h[j],mul(pri[i],del(h[get_id(w[j]/pri[i])],p[i-1]))); //sum of prime
}
for(int i=1;i<=m;i++) f[i]=del(g[i],h[i]);
} int calc(ll x,int i) {
if(x<=1||pri[i]>x) return 0;
int res=del(f[get_id(x)],del(p2[i-1],p[i-1]));
for(int j=i;1ll*pri[j]*pri[j]<=x;j++)
for(ll k=1,e=pri[j],ee=e;e*pri[j]<=x;e*=pri[j],k++,ee=e%mod) //注意e过大可能会爆,先模一下就好了
res=add(res,add(mul(mul(ee,ee-1),calc(x/e,j+1)),mul(mul(ee,pri[j]),del(mul(ee,pri[j]),1))));
return res;
} int main() {
scanf("%lld",&n);b=ceil(sqrt(n));
sieve();get_g();write(add(calc(n,1),1));
return 0;
}

min-25筛学习笔记的更多相关文章

  1. $Min\_25$筛学习笔记

    \(Min\_25\)筛学习笔记 这种神仙东西不写点东西一下就忘了QAQ 资料和代码出处 资料2 资料3 打死我也不承认参考了yyb的 \(Min\_25\)筛可以干嘛?下文中未特殊说明\(P\)均指 ...

  2. Min_25筛 学习笔记

    这儿只是一个简单说明/概括/总结. 原理见这: https://www.cnblogs.com/cjyyb/p/9185093.html https://www.cnblogs.com/zhoushu ...

  3. Powerful Number 筛学习笔记

    Powerful Number 筛学习笔记 用途 \(Powerful\ number\) 筛可以用来求出一类积性函数的前缀和,最快可以达到根号复杂度. 实现 \(Powerful\ number\) ...

  4. Min_25筛学习笔记

    感觉好好用啊 Luogu上的杜教筛模版题一发 Min_25抢到了 rank1 $ Updated \ on 11.29 $被 STO txc ORZ踩爆啦 前言 $ Min$_$25$筛可以求积性函数 ...

  5. 洲阁筛 & min_25筛学习笔记

    洲阁筛 给定一个积性函数$F(n)$,求$\sum_{i = 1}^{n}F(n)$.并且$F(n)$满足在素数和素数次幂的时候易于计算. 显然有: $\sum_{i = 1}^{n} F(n) = ...

  6. 莫比乌斯反演/线性筛/积性函数/杜教筛/min25筛 学习笔记

    最近重新系统地学了下这几个知识点,以前没发现他们的联系,这次总结一下. 莫比乌斯反演入门:https://blog.csdn.net/litble/article/details/72804050 线 ...

  7. Linux(10.18-10.25)学习笔记

    一.学习目标 1. 了解常见的存储技术(RAM.ROM.磁盘.固态硬盘等) 2. 理解局部性原理 3. 理解缓存思想 4. 理解局部性原理和缓存思想在存储层次结构中的应用 5. 高速缓存的原理和应用 ...

  8. Min_25 筛 学习笔记

    原文链接https://www.cnblogs.com/zhouzhendong/p/Min-25.html 前置技能 埃氏筛法 整除分块(这里有提到) 本文概要 1. 问题模型 2. Min_25 ...

  9. min_25筛学习笔记【待填坑】

    看见ntf和pb两位大佬都来学了,然后就不自觉的来学了. 我们考虑这样一个问题. $$ans=\sum_{i=1}^nf(i)$$其中$1\leq n\leq 10^{10}$ 其中$f(i)$是一个 ...

随机推荐

  1. 干货 | 10分钟掌握branch and cut(分支剪界)算法原理附带C++求解TSP问题代码

    00 前言 branch and cut其实还是和branch and bound脱离不了干系的.所以,在开始本节的学习之前,请大家还是要务必掌握branch and bound算法的原理. 01 应 ...

  2. 前端微信小程序仿菜谱精灵

    需求描述及交互分析 设计思路和相关知识点 底部标签导航设计 幻灯片轮播效果设计 菜谱专题列表显示设计 菜谱专题详情设计 菜谱分类设计 幻灯片轮播效果动态切换展示一些美食图片 若本号内容有做得不到位的地 ...

  3. Bacteria(优先队列)

    题目链接:http://codeforces.com/gym/101911/problem/C 问题简述:给定n个细胞以及每个细胞的大小,相同的细胞能进行融合,如果能融合到只剩1个细胞则输出需要额外增 ...

  4. Koa 脚手架创建项目

    Koa 脚手架创建项目 通过应用 koa 脚手架生成工具 可以快速创建一个基于 koa2 的应用的骨架 全局安装koa npm install koa-generator -g //必须安装到全局 创 ...

  5. [Beta]第十次 Scrum Meeting

    [Beta]第十次 Scrum Meeting 写在前面 会议时间 会议时长 会议地点 2019/5/20 22:00 20min 大运村公寓6F寝室 附Github仓库:WEDO 例会照片 工作情况 ...

  6. swoole流程图

    程图,便于以后回忆下 总结几点如下: 首先主进程监听pipe_master事件, 子进程监听pipe_worker事件 通过主进程派生的线程 swReactorThread *thread = swS ...

  7. 泡泡一分钟:GEN-SLAM - Generative Modeling for Monocular Simultaneous Localization and Mapping

    张宁  GEN-SLAM - Generative Modeling for Monocular Simultaneous Localization and Mapping GEN-SLAM  - 单 ...

  8. post 发送方式

    /** * post 方式 解码 */ public static String getWebContentByPost(String urlString, String data, final St ...

  9. Puppeteer最大化显示,分辨率自适应

    Puppeteer自适应分辨率,可以将defaultViewport设为null, 启动的时候还是半屏显示,点击最大化按钮,可以最大化显示. 这样分辨率能够自适应操作系统. 具体可看:https:// ...

  10. 123456123456#6#---###6%%%----com.zzj.DinosourKnown235---前拼show后广--恐龙百科-66666666

    com.zzj.DinosourKnown235---前拼show后广--恐龙百科-