LOJ #6202. 叶氏筛法(min_25 筛)
题意
求 \([L, R]\) 之间的素数之和 . \(L≤10^{10},2×10^{10} \le R \le 10^{11}\)
题解
一个有点裸的 min_25筛 ? 现在我只会筛素数的前缀和 , 合数的过几天再学吧 .
首先推荐一波 yyb大佬博客 这个人很强 , 别那么fake就好啦
令 \(F(x) = x\) 显然此处 \(F(x)\) 是完全积性函数 .
我们需要求的就是 $$\displaystyle \sum_{i=1}^{n} [i \in Prime] F(i)$$ .
这个就是 min_25筛的预处理部分 啦.
由 yyb博客 可得 .
对于下面这个表达式 ,
\]
有如下一个递推式 :
\]
这个直接实现是 \(\displaystyle O(\frac{n^{\frac{3}{4}}}{\log n})\) 的复杂度 qwq
然后考虑代码实现 .
首先预处理前 \(\sqrt n\) 的素数 , (假设处理到了 \(lim\) )
以及 \(i=1 \sim lim\) 的 \(F(x)\) 前缀和 . (此处可适当处理多一点 , 时间效率会提高)
然后假设我们当前考虑的是 \(g(n, m)\) .
直观上共有三步 .
- \(P_{m+1}^2 > n\) 且 \(n \le lim\) , 那么此时可以直接用之前预处理的答案 , 因为此时存在有贡献的数只可能为素数 .
- 将 \(m\) 一直缩小到 \(n < P_m^2\) . 这个利用了递推式 \(P_j^2 > n\) 时 \(g(n,j) = g(n, j - 1)\) 的那个定理 .
- 然后不断将 \(m\) 下降, 直至下降到 \(0\) , 此间需要要递归计算 \(P_{j}[g(\frac{n}{P_j},j-1)+g(P_j-1,j-1)]\) 的值 , 其中后者 \(g(P_j-1,j-1)\) 可以用前面预处理 , 递归下去也只会有一层 . 而前者会不断递归计算 . 其中 \(m\) 到 \(0\) 的时候 , 就是边界情况 : \(\displaystyle g(n, 0)=\sum_{i=2}^{n} i\) . 这个是很显然的 , 因为此时所有数都计入了贡献 , 但 \(1\) 是无法给予这个贡献的 . (一开始此处调试许久... )
代码
递归版本
直接按前面的式子模拟即可。
#include <bits/stdc++.h>
#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define debug(x) cout << #x << ':' << x << endl
using namespace std;
void File() {
#ifdef zjp_shadow
freopen ("6202.in", "r", stdin);
freopen ("6202.out", "w", stdout);
#endif
}
const int N = 1e7 + 1e3, Lim = 1e7;
typedef __int128 ll;
inline ll read() {
ll x = 0, fh = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
return x * fh;
}
inline void Out(ll x, bool fir = true) {
if (!x) { if (fir) puts("0"); return ; }Out(x / 10, false); putchar (x % 10 + 48); if (fir) putchar ('\n');
}
int prime[N], cnt = 0; bitset<N> is_prime;
ll sump[N];
void Init(int maxn) {
is_prime.set(); is_prime[0] = is_prime[1] = false;
For (i, 2, maxn) {
sump[i] = sump[i - 1];
if (is_prime[i])
prime[++ cnt] = i, sump[i] += i;
For (j, 1, cnt) {
register int res = i * prime[j];
if (res > maxn) break;
is_prime[res] = false;
if (!(i % prime[j])) break;
}
}
}
inline ll Sum(ll x) { return x * (x + 1) / 2 - 1; }
int tot = 0;
ll Sump(ll n, int m) {
if (n <= Lim && n < (ll)prime[m + 1] * prime[m + 1]) return sump[n];
for (; n < (ll)prime[m] * prime[m]; -- m);
ll res = Sum(n);
for (; m; -- m)
res -= (Sump(n / prime[m], m - 1) - /*Sump(prime[m] - 1, m - 1)*/ sump[prime[m] - 1]) * prime[m];
return res;
}
inline ll Calc(ll x) { return Sump(x, cnt - 1); }
int main () {
File();
Init(Lim);
ll l = read(), r = read(); Out(Calc(r) - Calc(l - 1));
return 0;
}
非递归版本
如何做非递归呢?
考虑每次的 \(j\) 都是不断减小的,就是我们会依次会除掉一个个质因子 \(p_j\) 。
我们从小到大枚举每个质因子 \(p_j \le \lfloor \sqrt n \rfloor\) ,然后再从小到大枚举每个 \(n\) 的块 \(\displaystyle \lfloor \frac{n}{x} \rfloor\) (只有 \(\sqrt n\) 个)。
然后利用上面的式子直接递推即可。
具体实现的时候由于只有 \(\sqrt n\) 个,我们对于 \(\le \sqrt n\) 的和 \(> \sqrt n\) 的进行分块即可。
#include <bits/stdc++.h>
#define For(i, l, r) for (register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for (register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Rep(i, r) for (register int i = (0), i##end = (int)(r); i < i##end; ++i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl
using namespace std;
//typedef long long ll;
typedef __int128 ll;
template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; }
inline ll read() {
ll x(0), sgn(1); char ch(getchar());
for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
return x * sgn;
}
inline void Out(ll x) {
if (!x) { puts("0"); }
char stk[25]; int top = 0;
for (; x; x /= 10) stk[++ top] = (x % 10) + 48;
while (top) putchar (stk[top --]); putchar ('\n');
}
void File() {
#ifdef zjp_shadow
freopen ("6202.in", "r", stdin);
freopen ("6202.out", "w", stdout);
#endif
}
const int N = sqrt(1e11) * 2 + 10;
bitset<N> is_prime;
int prime[N / 10], pcnt; ll sump[N / 10];
void Linear_Sieve(int maxn) {
is_prime.set();
is_prime[0] = is_prime[1] = false;
For (i, 2, maxn) {
if (is_prime[i]) {
prime[++ pcnt] = i;
sump[pcnt] = sump[pcnt - 1] + i;
}
for (int j = 1; j <= pcnt && 1ll * prime[j] * i <= maxn; ++ j) {
is_prime[prime[j] * i] = false; if (!(i % prime[j])) break;
}
}
}
int d, id1[N], id2[N];
ll val[N], res[N];
#define id(x) (x <= d ? id1[x] : id2[n / (x)])
inline ll Sum(ll n) {
return n * (n + 1) / 2 - 1;
}
ll Min25_Sieve(ll n) {
int cnt = 0; d = sqrt((long long)(n));
for (ll i = 1; i <= n; i = n / (n / i) + 1)
val[id(n / i) = ++ cnt] = n / i, res[cnt] = Sum(n / i);
For (i, 1, pcnt)
for (int j = 1; j <= cnt && 1ll * prime[i] * prime[i] <= val[j]; ++ j)
res[j] -= (res[id(val[j] / prime[i])] - sump[i - 1]) * prime[i];
return res[id(n)];
}
int main () {
File();
ll l = read(), r = read();
Linear_Sieve(sqrt(r + .5));
Out(Min25_Sieve(r) - Min25_Sieve(l - 1));
return 0;
}
LOJ #6202. 叶氏筛法(min_25 筛)的更多相关文章
- LOJ 6053 简单的函数——min_25筛
题目:https://loj.ac/problem/6053 min_25筛:https://www.cnblogs.com/cjyyb/p/9185093.html 这里把计算 s( n , j ) ...
- LOJ.6235.区间素数个数(Min_25筛)
题目链接 \(Description\) 给定\(n\),求\(1\sim n\)中的素数个数. \(2\leq n\leq10^{11}\). \(Solution\) Min_25筛.只需要求出\ ...
- LOJ.6053.简单的函数(Min_25筛)
题目链接 Min_25筛见这里: https://www.cnblogs.com/cjyyb/p/9185093.html https://www.cnblogs.com/zhoushuyu/p/91 ...
- loj 6053 简单的函数 —— min_25筛
题目:https://loj.ac/problem/6053 参考博客:http://www.cnblogs.com/zhoushuyu/p/9187319.html 算 id 也可以不存下来,因为 ...
- 【LOJ#572】Misaka Network 与求和(莫比乌斯反演,杜教筛,min_25筛)
[LOJ#572]Misaka Network 与求和(莫比乌斯反演,杜教筛,min_25筛) 题面 LOJ \[ans=\sum_{i=1}^n\sum_{j=1}^n f(gcd(i,j))^k\ ...
- 【LOJ#6682】梦中的数论(min_25筛)
[LOJ#6682]梦中的数论(min_25筛) 题面 LOJ 题解 注意题意是\(j|i\)并且\((j+k)|i\), 不难发现\(j\)和\((j+k)\)可以任意取\(i\)的任意因数,且\( ...
- 数论(8):min_25 筛(扩展埃氏筛)
min_25 筛介绍 我们考虑这样一个问题. \[ans=\sum_{i = 1}^nf(i)\\ \] 其中 \(1 \le n \le 10^{10}\) 其中 \(f(i)\) 是一个奇怪的函数 ...
- min_25筛
min_25筛 用来干啥? 考虑一个积性函数\(F(x)\),用来快速计算前缀和\[\sum_{i=1}^nF(i)\] 当然,这个积性函数要满足\(F(x),x\in Prime\)可以用多项式表示 ...
- [复习]莫比乌斯反演,杜教筛,min_25筛
[复习]莫比乌斯反演,杜教筛,min_25筛 莫比乌斯反演 做题的时候的常用形式: \[\begin{aligned}g(n)&=\sum_{n|d}f(d)\\f(n)&=\sum_ ...
随机推荐
- CF1097F Alex and a TV Show 莫比乌斯反演、bitset
传送门 发现自己对mobius反演的理解比较浅显-- 首先我们只需要维护每一个数的出现次数\(\mod 2\)的值,那么实际上我们只需要使用\(bitset\)进行维护,每一次加入一个数将其对应次数异 ...
- HNOI2019 白兔之舞 dance
HNOI2019 白兔之舞 dance 显然\(n=3\)就是\(n=1\)的扩展版本,先来看看\(n=1\)怎么做. 令\(W=w[1][1]\),显然答案是:\(ans_t=\sum_{i\mod ...
- R语言学习 第十篇:包
包(Package)是实现特定功能的.预先写好的代码库(library),通俗地说,包是含有函数.数据等的功能模块.R拥有大量的软件包,许多包都是由某一领域的专家编写的,但并不是所有的包都有很高的质量 ...
- JVM规范系列第3章:为Java虚拟机编译
Oracle 的 JDK 包括两部分内容:一部分是将 Java 源代码编译成 Java 虚拟机的指令集的编译器,另一部分是用于Java 虚拟机的运行时环境. 第一部分应该说的是 Javac 这个前置编 ...
- C# 读取Json配置文件
今天需要用到读取Json配置文件的helper 结果竟然没找到合适的 微软自己有一个 不过不支持.Net fw 4.0 于是自己在NewTonSoft.Json的基础上 加了点小小的封装 ...
- 新人入坑Redis必会的吐血总结
新人入坑Redis必会的吐血总结 一.什么是Redis Redis是一个使用C语言开发的开源的高性能的key-value存储系统,我们可以把它近似理解为Java Map.简单来讲,Redis是一种NO ...
- YouTube视频下载的12个软件(Win和Mac)
如今,观看视频已经成为人们生活中重要的一部分.很多时候,我们都需要用到视频,比如教育用途.会议报告.休闲娱乐以及广告宣传等.如果你觉得有时候资源不好找的话,不放去看下YouTube.YouTube是世 ...
- Docker管理工具 - Swarm部署记录
之前介绍了Docker集群管理工具-Kubernetes部署记录,下面介绍另一个管理工具Swarm的用法,Swarm是Docker原生的集群管理软件,与Kubernetes比起来比较简单. Swarm ...
- BugPhobia启程篇章:需求分析与功能定位
0x01 :引言 If you weeped for the missing sunset, you would miss all the shining stars 我看着大巴缓缓的驶过街角,我躲在 ...
- Hibernate_HQL
public class According_condition { public static void main(String[]args){ Session session=HibernateU ...