「学习笔记」Min25筛

前言

周指导今天模拟赛五分钟秒第一题,十分钟说第二题是 \(\text{Min25}​\) 筛板子题,要不是第三题出题人数据范围给错了,周指导十五分钟就 \(\text{AK}​\) 了,为了向 \(\text{AK}​\)王 学习,真诚的膜拜他,接受红太阳的指导,下午就学习了一下 \(\text{Min25}​\) 筛。

简介

如果 \(f(n)\) 是一个积性函数,且 \(f(n)\) 是一个关于 \(n\) 的简单多项式,并可以快速算出 \(f(p^k),\ p\text{ is prime, } k \geq 0\) 的值,那么大概可以用 \(\text{Min25}\) 筛在 \(\mathcal O(\frac{n^\frac{3}{4}}{log_n})\) 求出 \(\sum_{i=1}^nf(i)\) 的值。

算法

首先令 \(s\) 为所有 \(i\in[1,n], \lfloor\frac{n}{i}\rfloor\) 的集合,并试图预处理出 \(\forall x \in s \sum_{i=2}^x [i\text{ is prime}] f(i)\)

可能当 \(x\) 不是质数的时候,\(f(x)\) 不太好求,我们先假装所有数都是质数,然后用类似埃式筛法的过程把不是质数的 \(f(x)\) 值给筛掉。

具体的算法之前,先定义一些东西:

令 \(P=\{prime_1\dots prime_m\}\) 表示前 \(m\) 个质数的集合,并且 \(prime_{m+1}>\sqrt n\) 。

令 $g(n,k) ={\sum_{i=2}^n[i \text{ is prime}\text{ or } minp(i)>prime_k]}f(i) $ 表示前 \(n\) 个数中满足是质数或者最小质因子大于第 \(k\) 个质数的数假装它为质数求出来的 \(f(x)\) 之和。

\(g(n, k)​\) 的本质是筛掉了前 \(n​\) 个数筛去前 \(k​\) 个质数的倍数后剩下的那些数的 \(f(x)​\) 之和,显然,\(g(S,m)​\) 就是要预处理的东西。

可以通过这个东西求 \(g\) 了

\[g(n,k) = g(n,k-1)\ \ \ \ \ \ \text{if } prime_k > \sqrt n \\
g(n,k) = g(n,k-1)-f(prime_k)\times [g(\lfloor\frac{n}{prime_k}\rfloor,k-1)-\sum_{i=1}^{k-1} f(prime_i)]\ \ \ \ \ \ \text{if } prime_k \leq \sqrt n
\]

第一个转移显然,\(prime_k​\) 筛不掉任何数了,第二个转移考虑把所有在前 \(k-1​\) 轮最小质因子不为 \(prime_k​\) 的数贡献减掉,因为 \(f(x)​\) 是积性的直接搞就好了,因为 \(g(n,k)​\) 仍然要保留前 \(k-1​\) 个质数的贡献,所以还要加回来。

现在已经预处理出了 \(\forall x \in s \sum_{i=2}^x [i\text{ is prime}] f(i)​\) 的值,也就是我们求出了质数的答案,接下来通过从小到大加入质因子来求出合数的答案。

令 \(S(n,k)=\sum_{i=2}^n [minp(i)\geq k] f(i)\) ,这里的 \(f(i)\) 就是真实的值了,不假装他是质数,那么答案就是 \(f(1)+S(n,1)\) 。

质数的贡献之前已经算出来了,就是 \(g(n,m)-\sum_{i=1}^{k-1}f(prime_i)\)。

考虑枚举每个数的最小质因子以及它们幂次得到合数的转移

\[S(n,k)=g(n,m)-\sum_{i=1}^{k-1}f(prime_i)+\sum_{j=k}^m\sum_{t=1}^{prime_{j}^{t+1}\leq \ n}S(\lfloor\frac{n}{prime_j^t}\rfloor,j+1)\times f(prime_{j}^t)+f(prime_j^{t+1})
\]

其中 \(S(\lfloor\frac{n}{prime_j^t}\rfloor,j+1)\times f(prime_{j}^t)\) 算的是后面还有别的质因子的情况,\(f(prime_j^{t+1})\) 算的是后面没有别的质因子的情况,可以感性理解一下。

例题

「Loj6235」 区间素数个数

求 \([1,n]\) 的素数个数,\(n \leq10^{11}\)

令 \(f(x)\) 当 \(x\) 是质数的时候为 \(1\) ,\(x\) 是其它数的时候为 \(0\) ,虽然不满足这个东西是一个关于 \(x\) 的简单多项式,但是只求 \(f\) 是质数的时候的答案显然是对的,\(g(n,m)\) 就是答案。

code

/*program by mangoyang*/
#include <bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
#define ID(x) ((x) <= T ? id[0][(x)] : id[1][n/(x)])
const int N = 1000005;
ll prime[N], id[2][N], a[N], g[N], n, m, tot, T;
int b[N];
int main(){
read(n), T = sqrt(n);
for(ll l = 1; l <= n; l = n / (n / l) + 1){
a[++m] = n / l, g[m] = a[m] - 1;
id[a[m]<=T?0:1][a[m]<=T?a[m]:n/a[m]] = m;
}
for(int i = 2; i <= T; i++){
if(!b[i]) prime[++tot] = i;
for(int j = 1; j <= tot && i * prime[j] <= T; j++){
b[i*prime[j]] = 1;
if(i % prime[j] == 0) break;
}
}
for(int i = 1; i <= tot; i++)
for(int j = 1; j <= m && prime[i] * prime[i] <= a[j]; j++)
g[j] -= g[ID(a[j]/prime[i])] - (i - 1);
cout << g[ID(n)] << endl;
return 0;
}

「51NOD1222」 最小公倍数计数

令 \(f(n)=\sum_{i=1}^n\sum_{j=i}^n [\text{lcm}(i,j)=n]\),求 \(\sum_{i=a}^b f(i),a\leq b\leq 10^{11}\) 。

首先先令 \(f'(n)=\sum_{i=1}^n\sum_{j=1}^n[\text{lcm}(i,j)=n]\) ,显然 \(f(n)=\frac{f'(n)+n}{2}\) 。

\[\sum_{i=1}^n\sum_{j=1}^n[\text{lcm}(i,j)=n]\\
=\sum_{i|n}^n\sum_{j|n}^n[\frac{ij}{\gcd(i,j)}=n] \\
=\sum_{i|n}^n\sum_{j|n}^n[ij=\gcd(ni,nj)] \\
=\sum_{i|n}^n\sum_{j|n}^n[\gcd(\frac{n}{i},\frac{n}{j})=1] \\
=\sum_{i|n}^n\sum_{j|n}^n[\gcd(i,j)=1] \\
=\sum_{d|n}2^\omega(d)
\]

最后一步考虑组合意义,每一种质因子,要么全部归 \(i\) 要么全部归 \(j\) ,然后你会发现,\(f'(n)\) 是一个积性函数,且满足 \(f(prime_i^k)=2k+1\) ,直接 \(\text{Min25}\) 筛即可。

code

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 1000005;
namespace Min25{
#define id(x) ((x) <= T ? id1[x] : id2[n/(x)])
ll prime[N];
int b[N], tot, id1[N], id2[N], m;
ll a[N], g[N], T, n;
inline void init(){
m = tot = 0, T = sqrt(n + 0.5);
for(int i = 2; i <= T; i++){
if(!b[i]) prime[++tot] = i;
for(int j = 1; j <= tot && i * prime[j] <= T; j++){
b[i*prime[j]] = 1;
if(i % prime[j] == 0) break;
}
}
for(ll l = 1; l <= n; l = n / (n / l) + 1){
a[++m] = n / l;
if(a[m] <= T) id1[a[m]] = m; else id2[n/a[m]] = m;
g[m] = 3ll * (a[m] - 1);
}
for(int j = 1; j <= tot; j++)
for(int i = 1; i <= m && prime[j] * prime[j] <= a[i]; i++){
g[i] -= g[id(a[i]/prime[j])] - 3ll * (j - 1);
}
}
inline ll solve(ll a, ll b){
if(a < prime[b]) return 0;
ll ans = g[id(a)] - 3 * (b - 1);
for(int j = b; j <= tot && prime[j] * prime[j] <= a; j++)
for(ll p = prime[j], t = 1; p * prime[j] <= a; t++, p = p * prime[j])
ans += solve(a / p, j + 1) * (2 * t + 1) + 2 * t + 3;
return ans;
}
inline ll gao(ll x){
if(x == 0) return 0;
if(x == 1) return 1;
n = x, init();
return (solve(n, 1) + 1 + n) / 2ll;
}
}
int main(){
ll a, b;
cin >> a >> b;
cout << Min25::gao(b) - Min25::gao(a - 1) << endl;
return 0;
}

「学习笔记」Min25筛的更多相关文章

  1. 「学习笔记」min_25筛

    前置姿势 魔力筛 其实不看也没关系 用途和限制 在\(\mathrm{O}(\frac{n^{0.75}}{\log n})\)的时间内求出一个积性函数的前缀和. 所求的函数\(\mathbf f(x ...

  2. 「学习笔记」FFT 之优化——NTT

    目录 「学习笔记」FFT 之优化--NTT 前言 引入 快速数论变换--NTT 一些引申问题及解决方法 三模数 NTT 拆系数 FFT (MTT) 「学习笔记」FFT 之优化--NTT 前言 \(NT ...

  3. 「学习笔记」FFT 快速傅里叶变换

    目录 「学习笔记」FFT 快速傅里叶变换 啥是 FFT 呀?它可以干什么? 必备芝士 点值表示 复数 傅立叶正变换 傅里叶逆变换 FFT 的代码实现 还会有的 NTT 和三模数 NTT... 「学习笔 ...

  4. 「学习笔记」Treap

    「学习笔记」Treap 前言 什么是 Treap ? 二叉搜索树 (Binary Search Tree/Binary Sort Tree/BST) 基础定义 查找元素 插入元素 删除元素 查找后继 ...

  5. 「学习笔记」字符串基础:Hash,KMP与Trie

    「学习笔记」字符串基础:Hash,KMP与Trie 点击查看目录 目录 「学习笔记」字符串基础:Hash,KMP与Trie Hash 算法 代码 KMP 算法 前置知识:\(\text{Border} ...

  6. 「学习笔记」wqs二分/dp凸优化

    [学习笔记]wqs二分/DP凸优化 从一个经典问题谈起: 有一个长度为 \(n\) 的序列 \(a\),要求找出恰好 \(k\) 个不相交的连续子序列,使得这 \(k\) 个序列的和最大 \(1 \l ...

  7. 「学习笔记」ST表

    问题引入 先让我们看一个简单的问题,有N个元素,Q次操作,每次操作需要求出一段区间内的最大/小值. 这就是著名的RMQ问题. RMQ问题的解法有很多,如线段树.单调队列(某些情况下).ST表等.这里主 ...

  8. 「学习笔记」递推 & 递归

    引入 假设我们想计算 \(f(x) = x!\).除了简单的 for 循环,我们也可以使用递归. 递归是什么意思呢?我们可以把 \(f(x)\) 用 \(f(x - 1)\) 表示,即 \(f(x) ...

  9. 「学习笔记」动态规划 I『初识DP』

    写在前面 注意:此文章仅供参考,如发现有误请及时告知. 更新日期:2018/3/16,2018/12/03 动态规划介绍 动态规划,简称DP(Dynamic Programming) 简介1 简介2 ...

随机推荐

  1. ASP.Net Cache(缓存)—ASP.NET细枝末节(2)

    概述 1.意义 把数据放到Cache中,在指定的时间内,可以直接从Cache中获取,避免对数据库等的压力. 2.做法 设置: HttpRuntime.Cache.Insert(CacheKey, ob ...

  2. 用ajax、PHP、session做购物车

    购物车网页代码 1.登录界面login.php <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ...

  3. 大数加法(SDUT“斐波那契”串)4335

    题目链接:https://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Contest/contestproblem/cid/2697/pid/4335.ht ...

  4. Struts访问servletAPI方式

    1.原理

  5. 做php网站后台开发,在Linux系统上进行更好吗?【转载】

    1. PHP是开源软件,它在bsd/linux/win下都有很好的正式版及孪生版.并非开发php就必须要在linux下进行.主机服务商们习惯性的把asp与php分为两个主机系列几进行销售.由于asp只 ...

  6. C#子线程中更新ui-----c# 多线程多文件批量下载

    c# 多线程多文件批量下载   废话少说,先演示一张效果图 简单说下过程喽 开发过程中其实总是会碰到项目想应用下载文件~ 看其他语言有很多封装好的类库可以使用~~ 作为小白的我并没有找到很多c#的案例 ...

  7. CGI、FastCGI和php-fpm的概念和区别

    CGI是HTTP Server和一个独立的进程之间的协议,把HTTP Request的Header设置成进程的环境变量,HTTP Request的正文设置成进程的标准输入,而进程的标准输出就是HTTP ...

  8. python 多线程, 多进程, 协程

    1. 介绍: threading用于提供线程相关的操作,线程是应用程序中工作的最小单元.python当前版本的多线程库没有实现优先级.线程组,线程也不能被停止.暂停.恢复.中断. 2. 1  线程执行 ...

  9. tomcat报错HTTP Status 405 - HTTP method GET is not supported by this URL

    servlet提交表单,结果出错. 出现HTTP Status 405 - HTTP method GET is not supported by this URL 原因是:1.继承自Httpserv ...

  10. C++ 静多态与动多态

    多态是指通过单一的标识支持不同的特定行为的能力. C++中有两种多态,称为动多态(运行期多态)和静多态(编译期多态),而静多态主要通过模板来实现,宏也是实现静多态的一种途径. 动多态在C++中是通过虚 ...