「学习笔记」Min25筛
「学习笔记」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)-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(\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|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筛的更多相关文章
- 「学习笔记」min_25筛
前置姿势 魔力筛 其实不看也没关系 用途和限制 在\(\mathrm{O}(\frac{n^{0.75}}{\log n})\)的时间内求出一个积性函数的前缀和. 所求的函数\(\mathbf f(x ...
- 「学习笔记」FFT 之优化——NTT
目录 「学习笔记」FFT 之优化--NTT 前言 引入 快速数论变换--NTT 一些引申问题及解决方法 三模数 NTT 拆系数 FFT (MTT) 「学习笔记」FFT 之优化--NTT 前言 \(NT ...
- 「学习笔记」FFT 快速傅里叶变换
目录 「学习笔记」FFT 快速傅里叶变换 啥是 FFT 呀?它可以干什么? 必备芝士 点值表示 复数 傅立叶正变换 傅里叶逆变换 FFT 的代码实现 还会有的 NTT 和三模数 NTT... 「学习笔 ...
- 「学习笔记」Treap
「学习笔记」Treap 前言 什么是 Treap ? 二叉搜索树 (Binary Search Tree/Binary Sort Tree/BST) 基础定义 查找元素 插入元素 删除元素 查找后继 ...
- 「学习笔记」字符串基础:Hash,KMP与Trie
「学习笔记」字符串基础:Hash,KMP与Trie 点击查看目录 目录 「学习笔记」字符串基础:Hash,KMP与Trie Hash 算法 代码 KMP 算法 前置知识:\(\text{Border} ...
- 「学习笔记」wqs二分/dp凸优化
[学习笔记]wqs二分/DP凸优化 从一个经典问题谈起: 有一个长度为 \(n\) 的序列 \(a\),要求找出恰好 \(k\) 个不相交的连续子序列,使得这 \(k\) 个序列的和最大 \(1 \l ...
- 「学习笔记」ST表
问题引入 先让我们看一个简单的问题,有N个元素,Q次操作,每次操作需要求出一段区间内的最大/小值. 这就是著名的RMQ问题. RMQ问题的解法有很多,如线段树.单调队列(某些情况下).ST表等.这里主 ...
- 「学习笔记」递推 & 递归
引入 假设我们想计算 \(f(x) = x!\).除了简单的 for 循环,我们也可以使用递归. 递归是什么意思呢?我们可以把 \(f(x)\) 用 \(f(x - 1)\) 表示,即 \(f(x) ...
- 「学习笔记」动态规划 I『初识DP』
写在前面 注意:此文章仅供参考,如发现有误请及时告知. 更新日期:2018/3/16,2018/12/03 动态规划介绍 动态规划,简称DP(Dynamic Programming) 简介1 简介2 ...
随机推荐
- LintCode 510: Maximal Rectangle
LintCode 510: Maximal Rectangle 题目描述 给你一个二维矩阵,权值为False和True,找到一个最大的矩形,使得里面的值全部为True,输出它的面积 Wed Nov 2 ...
- python学习笔记(十二)之函数
牛刀小试: 定义一个无参函数 >>> def myFirstFunc(): ... print("Hello python") ... print("h ...
- 天梯赛 L2-006 树的遍历 (二叉树)
给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列.这里假设键值都是互不相等的正整数. 输入格式: 输入第一行给出一个正整数N(<=30),是二叉树中结点的个数.第二行给出其后序遍历序 ...
- Tinyos 第三版Make系统
1.make系统安装 cd tools ./Bootstrap ./configure make sudo make install 2.make系统结构 3.第三版Makerules文件部分解析 # ...
- (5)剑指Offer之栈变队列和栈的压入、弹出序列
一 用两个栈实现队列 题目描述: 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 问题分析: 先来回顾一下栈和队列的基本特点: 栈:后进先出(LIFO) 队列: ...
- python基础===python自带idle的快捷键
Ctrl + [ Ctrl + ] 缩进代码Alt+3 Alt+4 注释.取消注释代码行Alt+5 Alt+6 切换缩进方式 空格<=>TabAlt+/ 单词完成,只要文中出现过,就可 ...
- 理解HTTP幂等性(转)
原文链接:http://www.cnblogs.com/weidagang2046/archive/2011/06/04/2063696.html
- 用OpenSSL命令行生成证书文件
用OpenSSL命令行生成证书文件 1.首先要生成服务器端的私钥(key文件): openssl genrsa -des3 -out server.key 1024 运行时会提示输入密码,此密码用于加 ...
- [Linux: vim]vim自动生成html代码
如果直接将vim编辑的文字复制粘贴到一些blog的编辑器中,这些代码将会是死板的白纸黑字.如果能加入关键字高亮功能就好了,这样代码阅读起来会很方便.一些blog的编辑器提供了这项功能,一些没有,一些支 ...
- Codefroces 919D Substring(拓扑排序+DP)
题目链接:http://codeforces.com/problemset/problem/919/D 题目大意:给你一张有向图,给你每个顶点上的字母和一些边,让你找出一条路径,路径上的相同字母数最多 ...