数论(8):min_25 筛(扩展埃氏筛)

时间:2022-08-26 21:29:09

min_25 筛介绍

我们考虑这样一个问题。

\[ans=\sum_{i = 1}^nf(i)\\
\]

其中 \(1 \le n \le 10^{10}\)

其中 \(f(i)\) 是一个奇怪的函数、并不像 \(μ(i),φ(i),iφ(i)\)那样具有那么好的性质。但是满足以下条件:

  1. 若 \(p\)为质数,则 \(f(p)\)是一个关于 \(p\)的多项式,比如 \(μ(p)=−1,φ(p)=p−1\).
  2. 若 \(p\)为质数,\(e\)为正整数,则 \(f(pe)\)可以很快求出。(通常是 \(O(1)\))
  3. \(f(n)\)为积性函数。

什么是积性函数:对于所有互质的 \(a\) 和 \(b\) ,总有 \(f(ab)=f(a)f(b)\) ,则称 \(f(x)\) 为积性函数。

然后就可以使用 min_25 筛了。(顾名思义是 min_25 发明的)

数论(8):min_25 筛(扩展埃氏筛)

首先,我们需要知道 min_25 筛是埃氏筛的一个拓展,它的思想很大一部分借助于埃氏筛。

回想一下埃氏筛,我们是每次将最小质因子为 \(P_i\) 的合数筛去,剩下的就是质数。

我们知道这些最小质因子至多为 \(\sqrt{n}\),所以合数可以通过枚举最小质因子来计算,质数我们则使用另外的方法。

数论(8):min_25 筛(扩展埃氏筛)

首先我们看质数的怎么做。

\[\sum_{i = 1}^n[i \in Prime]f(i)
\]

根据条件 \(1\),我们知道 \(f(i)\)是一个多项式,这样的话我们可以按照次数将 \(f(i)\)拆成 \(i^k\) 之和,因为 \(i^k\) 是一个完全积性函数(很快就有用的)。

\[\sum_{i = 1}^n[i \in Prime]i^k
\]

为了计算这个,我们需要引入一个辅助数组 \(g(n,j)\)。(鬼知道是怎么想到的)

\[g(n,j) = \sum_{i = 1}^n[i \in Prime or minp(i) > P_j]i^k
\]

其中 \(minp(i)\)表示 \(i\)的最小质因子,所以

\[\sum_{i = 1}^n[i \in Prime]i^k = g(n,|P|)
\]

既然我们要使用质数,所以我们可以先用欧拉筛把所有 \(\le \sqrt{n}\) 的质数筛出来,同时还要预处理 \(∑^j_{i=1}[i\in Prime]i^k\).

我们考虑 dp 计算。既然是埃氏筛,我们就要在 \(g(n,j−1)\)中最小质因子为 \(P_j\)的合数筛去。

我们假设 \(P_j^2 \le n\),否则肯定不行。

首先,由于它是完全积性函数,所以 \(P_j\) 可以直接提出来,剩下的减去 \(i≤⌊\frac{n}{P_j}⌋\)中的数就可以了。

这些数中要求质因子 \(≥P_j\),所以是 \(g(⌊\frac{n}{P_j}⌋,j−1)\),但是这里面质数被重复计算了,所以要减去里面的质数。

\[g(n,j) = g(n,j - 1) - P_j^k(g\lfloor{\frac{n}{P_j}} \rfloor,j - 1) - \sum_{i = 1}^{j - 1}[i \in Prime]i^k
\]

但是这样的话是 \(O(n∗|P|)\)的,时间和空间都承受不了。但是我们发现我们可以使用一个优化。

我们发现 \(g(n,j)\)中 \(n\)只有 \(O(\sqrt{n})\)种取值,因为每次递归的时候是 \(n\)变为 \(⌊\frac{n}{P_j}⌋\),而我们发现

\[\lfloor\frac{\lfloor\frac{a}b\rfloor}{c}\rfloor = \lfloor\frac{a}{bc}\rfloor
\]

所以 \(n\)只会变为 \(⌊nx⌋\),于是我们就直接 “手动” 离散化,这个可以看代码。

然后 \(g(n,j)\)的第二维也可以滚动数组滚掉。所以时间 \(O(\sqrt{n}∗|P|)\),空间 \(\sqrt{n}\) .

数论(8):min_25 筛(扩展埃氏筛)

预处理部分终于结束了,接下来我们考虑计算答案,首先我们还是需要一个辅助数组。

\[S(n,j) = \sum_{i = 1}^n[minp(i) > P_j]f(i)
\]

像上面说的一样,分质数和合数两类计算。

数论(8):min_25 筛(扩展埃氏筛)

前面两项指的是质数的部分,后面的和式是枚举合数的最小质因子 \(P_k\)和它的次数 \(e\),

这个跟 \(g\)不同,\(S\)是要按照第二维倒着计算的,但是我们也可以使用递归的方法来计算。

\(S(n,0)\)就是最终答案。

要注意的是,\(1\)既不是质数也不是合数,所以最后要加上。


至于上面说的那个手动离散化,我们要开两个数组 \(id1\)和 \(d2\),分别记录 \(≤ \sqrt{n}\) 和 \(>\sqrt{n}\)的部分的数值的编号。这样就不用 map 了,可以省掉一个 log

至于时间复杂度?我也不知道,总之跟杜教筛差不多,甚至有时候比杜教筛还要快。

有人说是什么 \(O\left(\frac{n^{\frac{3}{4}}}{\log{n}}\right)\) ,或者什么 \(O\left(n^{1 - \epsilon}\right)\) 。总之差不多就可以了。

min_25 筛代码实现:

#include<bits/stdc++.h>
#define Rint register LL
using namespace std;
typedef long long LL;
const int N = 1000003, mod = 1e9 + 7, inv2 = 500000004, inv3 = 333333336;
LL n, Sqr, pri[N], tot, pre1[N], pre2[N], ind1[N], ind2[N], g1[N], g2[N], w[N], cnt;
bool notp[N];
inline void init(LL m){
notp[0] = notp[1] = true;
for(Rint i = 2;i <= m;i ++){
if(!notp[i]){
pri[++ tot] = i;
pre1[tot] = (pre1[tot - 1] + i) % mod;
pre2[tot] = (pre2[tot - 1] + i * i) % mod;
}
for(Rint j = 1;j <= tot && i * pri[j] <= m;j ++){
notp[i * pri[j]] = true;
if(!(i % pri[j])) break;
}
}
}
inline LL S(LL x, int y){
if(pri[y] >= x) return 0;
LL k = (x <= Sqr) ? ind1[x] : ind2[n / x];
LL ans = (g2[k] - g1[k] + pre1[y] - pre2[y] + mod + mod) % mod;
for(Rint i = y + 1;i <= tot && pri[i] * pri[i] <= x;i ++){
LL pe = pri[i];
for(Rint e = 1;pe <= x;e ++, pe *= pri[i]){
LL xx = pe % mod;
ans = (ans + xx * (xx - 1) % mod * (S(x / pe, i) + (e > 1))) % mod;
}
}
return ans % mod;
}
int main(){
scanf("%lld", &n);
Sqr = sqrt(n);
init(Sqr);
for(Rint i = 1, last;i <= n;i = last + 1){
last = n / (n / i);
w[++ cnt] = n / i;
LL xx = w[cnt] % mod;
g1[cnt] = (xx * (xx + 1) / 2 + mod - 1) % mod;
g2[cnt] = (xx * (xx + 1) / 2 % mod * (2 * xx + 1) % mod * inv3 % mod + mod - 1) % mod;
if(n / i <= Sqr) ind1[w[cnt]] = cnt;
else ind2[last] = cnt;
}
for(Rint i = 1;i <= tot;i ++)
for(Rint j = 1;j <= cnt && pri[i] * pri[i] <= w[j];j ++){
LL k = (w[j] / pri[i] <= Sqr) ? ind1[w[j] / pri[i]] : ind2[n / (w[j] / pri[i])];
g1[j] -= pri[i] * (g1[k] - pre1[i - 1] + mod) % mod;
g2[j] -= pri[i] * pri[i] % mod * (g2[k] - pre2[i - 1] + mod) % mod;
if(g1[j] < 0) g1[j] += mod;
if(g2[j] < 0) g2[j] += mod;
}
printf("%lld", (S(n, 0) + 1) % mod);
}

讲那么多,写道题练手吧

数论(8):min_25 筛(扩展埃氏筛)

UOJ188#【UR #13】Sanrd

题目链接:UOJ

这道题,也算是 min_25 的一个基础应用吧。。。

我们要求

\[\sum_{i = 1}^nf(i)
\]

,其中 \(f(i)\)表示 \(i\)的次大质因子。

按照套路,我们设

\[S(n,j) = \sum_{i = 1}^n[minp(i) > P_j]f(i)
\]

所以

数论(8):min_25 筛(扩展埃氏筛)

素数个数用 min_25 筛可以很快求出来。

#include<bits/stdc++.h>
#define Rint register LL
using namespace std;
typedef long long LL;
const int N = 1000003;
LL Sqr, pri[N], tot, g[N], w[N], id1[N], id2[N], cnt;
bool notp[N];
inline void init(int m){
notp[0] = notp[1] = true;
for(Rint i = 2;i <= m;i ++){
if(!notp[i]) pri[++ tot] = i;
for(Rint j = 1;j <= tot && i * pri[j] <= m;j ++){
notp[i * pri[j]] = true;
if(!(i % pri[j])) break;
}
}
}
inline LL solve(LL n, LL x, int y){
if(x <= 1) return 0;
LL ans = 0;
for(Rint k = y + 1;k <= tot && pri[k] * pri[k] <= x;k ++){
for(Rint pe = pri[k];pe * pri[k] <= x;pe *= pri[k]){
LL kk = (x / pe <= Sqr) ? id1[x / pe] : id2[n / (x / pe)];
ans += solve(n, x / pe, k) + pri[k] * (g[kk] - k + 1);
}
}
return ans;
}
inline LL solve(LL n){
Sqr = sqrt(n);
tot = cnt = 0;
init(Sqr);
for(Rint i = 1, last;i <= n;i = last + 1){
w[++ cnt] = n / i;
last = n / w[cnt];
g[cnt] = w[cnt] - 1;
if(w[cnt] <= Sqr) id1[w[cnt]] = cnt;
else id2[last] = cnt;
}
for(Rint i = 1;i <= tot;i ++)
for(Rint j = 1;j <= cnt && pri[i] * pri[i] <= w[j];j ++){
LL k = (w[j] / pri[i] <= Sqr) ? id1[w[j] / pri[i]] : id2[n / (w[j] / pri[i])];
g[j] -= g[k] - i + 1;
}
return solve(n, n, 0);
}
int main(){
LL l, r;
scanf("%lld%lld", &l, &r);
printf("%lld\n", solve(r) - solve(l - 1));
}

参考

OI wiki:https://oi-wiki.org/math/min-25/

新版min25筛(O(n^(2/3)))详解:https://zhuanlan.zhihu.com/p/60378354

LaTeX数学公式大全:https://www.luogu.com.cn/blog/IowaBattleship/latex-gong-shi-tai-quan

数论(8):min_25 筛(扩展埃氏筛)的更多相关文章

  1. CodeForces - 385C Bear and Prime Numbers &lpar;埃氏筛的美妙用法&rpar;

    Recently, the bear started studying data structures and faced the following problem. You are given a ...

  2. cf1154G 埃氏筛应用

    直接用埃氏筛也可以做,但是这题写起来有点恶臭.. 更加简单的写法是直接枚举gcd=k,然后里面再枚举一次i*k,即找到k两个最小的倍数,看起来复杂度很高,但其实也是埃氏筛的复杂度 因为每次枚举gcd, ...

  3. 「CF779B」「LOJ&num;10201&period;」「一本通 6&period;2 练习 4」Sherlock and His Girlfriend(埃氏筛

    题目描述 原题来自:Codeforces Round #400 B. Sherlock 有了一个新女友(这太不像他了!).情人节到了,他想送给女友一些珠宝当做礼物. 他买了 nnn 件珠宝.第 iii ...

  4. &lbrack;JXOI 2018&rsqb; 游戏 解题报告 &lpar;组合数&plus;埃氏筛&rpar;

    interlinkage: https://www.luogu.org/problemnew/show/P4562 description: solution: 注意到$l=1$的时候,$t(p)$就 ...

  5. 埃氏筛优化&lpar;速度堪比欧拉筛&rpar; &plus; 洛谷 P3383 线性筛素数 题解

    我们一般写的埃氏筛消耗的时间都是欧拉筛的三倍,但是欧拉筛并不好想(对于我这种蒟蒻) 虽然 -- 我 -- 也可以背过模板,但是写个不会的欧拉筛不如写个简单易懂的埃氏筛 于是就有了优化 这个优化还是比较 ...

  6. 埃氏筛&plus;线段树——cf731F

    从2e5-1依次枚举每个数作为主显卡,然后分段求比它大的数的个数,这里的复杂度是调和级数ln2e5,即埃氏筛的复杂度.. #include<bits/stdc++.h> using nam ...

  7. U138097 小鱼吃大鱼 埃氏筛

    题目描述 小P同学在养殖一种非常凶狠的鱼,而且与其他鱼类不同,这种鱼越大越温顺,反而小鱼最凶残.当两条鱼相遇时, 小鱼会不断撕咬大鱼,每一口都咬下与它自身等重的肉(小鱼保持体重不变),直到大鱼的体重小 ...

  8. 【埃氏筛】洛谷P3383埃氏筛模板

    思路: 如果我们要筛出 [1, n] 内的所有素数,使用 [1, √n] 内的素数去筛就可以了 设bool型数组 a,a[i] 表示 i 是否被某个素数筛过 从 2 开始枚举每个数 i: 若 a[i] ...

  9. hdu&period;5212&period;Code&lpar;莫比乌斯反演 &amp&semi;&amp&semi; 埃氏筛)

    Code Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submi ...

随机推荐

  1. Reapp - 下一代的 Hybrid App 开发框架

    Reapp 与 React Native 有着惊人的相似之处,二者都使用 React 来创建应用程序用户界面的框架.然而,在底层机制上这两个框架之间却具有明显的哲学差异.React Native 将 ...

  2. EF Repository Update

    问题描述: 解决办法: http://www.cnblogs.com/scy251147/p/3688844.html 原理: Attaching an entity of type '' faile ...

  3. 转 关于ruby gem无法连接到rubygems&period;org的解决方案

    为什么有这个? 由于国内网络原因(你懂的),导致 rubygems.org 存放在 Amazon S3 上面的资源文件间歇性连接失败.所以你会与遇到 gem install rack 或 bundle ...

  4. Jndi使用好处,与简单实例【JBOSS】

    JNDI是 Java 命名与目录接口(Java Naming and Directory Interface),在J2EE规范中是重要的规范之一,不少专家认为,没有透彻理解JNDI的意义和作用,就没有 ...

  5. Jenkins与代码上线解决方案

    Jenkins是一个用Java编写的开源的持续集成工具.在与Oracle发生争执后,项目从Hudson项目独立. Jenkins提供了软件开发的持续集成服务.它运行在Servlet容器中(例如Apac ...

  6. js ES6 Set和Map数据结构详解

    这篇文章主要介绍了ES6学习笔记之Set和Map数据结构,结合实例形式详细分析了ECMAScript中基本数据结构Set和Map的常用属性与方法的功能.用法及相关注意事项,需要的朋友可以参考下   本 ...

  7. Lotusscript统计在线用户数

    使用notessession的SendConsoleCommand方法向服务器控制台发送“show inetusers”命令,该命令返回一个结果(字符串),字符串类似如下: admin   192.1 ...

  8. ICE简介及C&plus;&plus;程序例子&lpar;转&rpar;

    一.ICE简介: 1.ICE是什么? ICE是ZEROC的开源通信协议产品,它的全称是:The Internet Communications Engine,翻译为中文是互联网通信引擎,是一个面向对象 ...

  9. HDU 6463&period;超级无敌简单题-卡边界的暴力 &lpar;&OpenCurlyDoubleQuote;字节跳动-文远知行杯”广东工业大学第十四届程序设计竞赛&rpar;

    超级无敌简单题 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Sub ...

  10. C语言中 ln(以自然对数e为底) lg&lpar;以十为底&rpar; 以及logab(以a为底,b为真数)的相关知识

    总所周知,我们在高中学过对数函数,记作y=logax.下面是百度百科关于对数函数的描述: 对数的定义:一般地,如果ax=N(a>0,且a≠1),那么数x叫做以a为底N的对数,记作x=logaN, ...