Min_25 筛小结

Min_25 筛这个东西,完全理解花了我很长的时间,所以写点东西来记录一些自己的理解。

它能做什么

对于某个数论函数 \(f\),如果满足以下几个条件,那么它就可以用 Min_25 筛来快速求出这个函数的前缀和。

  1. 它是一个积性函数

  2. 对于一个质数 \(p\)\(f(p)\) 的表达式必须是一个项数比较小的多项式。即 \(\displaystyle f(p) = \sum a_ip^{b_i}\)

  3. 对于一个质数 \(p\)\(f(p^k)\) 的表达式必须可以由 \(f(p)\) 快速得到。

看起来这些条件比较紧,其实仔细想想许多函数还是满足这些性质的。接下来讨论它的实现过程。

实现过程

Min_25 筛的核心思想就是对于 \(\le n\) 的数中,除掉质数之后,每个数的最小质因子大小不超过 \(\sqrt{n}\) 。即类似埃氏筛的方式,从每个质因子筛掉一部分的贡献。整个过程可以分成三部分,即质数的部分的贡献之和与合数的部分的贡献和,以及 \(1\) 的特判。

记号约定

这里用 \(P\) 表示质数集合,\(P_i\) 表示第 \(i\) 小的质数。

质数部分

首先我们不妨设 \(f(p) = p^k\) 。对于更加一般的项数小的多项式形式,我们可以分别记每一个项的贡献,然后分别相加。注意到这里 \(f(p)\) 是一个完全积性函数。对于 \(p\) 为合数的情况,为了方便,我们先姑且同样定义 \(f(p) = p^k\) ,到最后你会明白这样定义的原因。

我们再设 \(g(n,i)\) 表示 \(\le n\) 的所有数 \(x\) 中,\(x\) 的最小质因子 \(> P_i\) 或者 \(x\) 本身为质数的所有 \(f(x)\) 之和,这样 \(g(n,|P|)\) 就是所有质数的贡献之和了。而 \(g(n,0)\) 的答案也十分显然,即 \(\displaystyle \sum_{i = 2} ^{n} i^k\) 。我们只需要考虑,如何从 \(g(*,i - 1)\) 如何得到 \(g(*,i)\)

考虑我们从 \(i - 1\) 推到 \(i\) 的过程中,会减少哪个部分的贡献,容易发现最小质因子恰好为 \(P_i\) 的贡献被减掉了。如果 \(P_i^2 > n\) ,那么这一部分是没有贡献的,即 \(g(n,i) = g(n,i - 1)\)

对于 \(P_i^2 \le n\) 的情况,我们需要把所有 \(P_i\) 的倍数,且满足其最小质因子除去 \(P_i\) 之外 \(> P_{i-1}\) 的贡献全部减掉。如果直接减去 \(f(P_i) \cdot g(\lfloor\frac{n}{P_i}\rfloor,i - 1)\) 你会发现贡献是减多了的,原因就是 \(g\) 函数的值还包含了所有质数的贡献之和,仔细分析一下,可以发现,对于 \(x = P_iP_j(j < i)\) 的贡献在 \(j\) 这个地方已经减过了,所以还要加回来,即 \(\displaystyle f(P_i) \cdot g(P_i - 1,i - 1) = \sum_{j = 1}^{i - 1} f(P_i)f(P_j)\)

式子汇总起来也就是
\[ g(n,i) = \begin{cases} g(n,i-1) & P_i^2>n \\ g(n,i-1) - f(P_i) (g(\lfloor\frac{n}{P_i}\rfloor,i - 1) - g(P_i - 1,i - 1)) & P_i^2 \le n \end{cases} \]
回头来,我们再来看最初我们提出的一些问题。

我们最开始为什么要定义,对于一个合数 \(p\)\(f(p) = p^k\) 呢?无非就是方便计算,方便利用完全积性函数的性质。你发现到最后,合数的贡献还是没有算进去,所以对于合数的定义是无所谓的。

我们到底在哪里利用了 \(f(p)\) 是一个完全积性函数的性质呢?这个性质是在上式中第二种情况中利用到的。注意到我们在减贡献的时候,并没有枚举 \(P_i\) 的次数,这也就意味着 \(g(\lfloor\frac{n}{P_i}\rfloor,i - 1)\) 中可能包含了某些数仍然是 \(P_i\) 的倍数。所以这一步需要有一个对于所有质数 \(p,f(p^2) = f^2(p)\) 的条件。由于之前我们假定了 \(f(p)\) 对于 \(p\) 为合数的情况也满足 \(f(p) = p^k\) ,因此这个条件是得到满足了的。

递归实现很显然。考虑一下非递归的实现。首先对于这个步骤,我们有用的 \(n\) 只有所有不同的 \(\lfloor\frac{n}{i}\rfloor,(1 \le i \le n)\),所以可以离散掉这些值,用一个大小为 \(2\sqrt{n}\) 的数组存下来。由于这个递推是一层一层推的,所以实现上可以不用开二维数组,可以直接离散之后用一个一维数组存下来,需要注意枚举顺序。

合数部分

考虑我们在求质数部分的时候,除了质数的答案之和之外,还求出了些什么东西。事实上,对于所有的 \(\lfloor\frac{n}{i}\rfloor,(1 \le i \le n)\) ,我们求出了 \(g(\lfloor\frac{n}{i}\rfloor,|P|)\) 的值。

我们设 \(S(n,i)\) 表示 \(\le n\) 的所有数 \(x\) 中,\(x\) 的最小质因子 \(\ge P_i\)\(f(x)\) 之和。注意这里的 \(f(x)\)\(x\) 为合数的时候不再沿用质数部分时的定义,也注意这里的定义与 \(g\) 的区别。

接下来我们先算上所有满足条件的质数贡献之和,即 \(\displaystyle g(n,|P|) - \sum_{j = 1}^{i - 1} f(P_j)\) 。对于合数,我们直接枚举其最小质因子以及质因子的个数,直接递归计算。注意在这里形如 \(p^k,(p \in P)\) 的贡献并没有算进去,所以还要单独加一下。式子的形式如下:
\[ S(n,i)=g(n,|P|)-\sum_{j=1}^{i-1}f(P_j)+\sum_{k\ge i}^{|P|}\sum_{e}(f(P_k^e)S(\lfloor\frac{n}{P_k^e}\rfloor,k+1)+f(P_{k}^{e+1})) \]
直接对着式子看,应该还是很好理解的。对这个式子,直接递归暴力计算即可,跑得会比第一部分快。

至此 Min_25 筛的全过程就讲完了。时间复杂度是 \(\displaystyle O(\frac{n^{\frac{3}{4}}}{\log n})\) 的,不大会证……

例题

首先可以用一个小问题来感受 Min_25 筛的威力。

SPOJ DIVCNT2

题意


\[ \sum_{i = 1}^{n} \sigma_0(i^2) \]
其中 \(\sigma_0(i)\) 表示 \(i\) 的约数个数。

\(n \le 10^{12},TimeLimit = 20s\)

题解

传统的杜教筛做法需要考虑将式子拆为每个质因子贡献相乘,然后反演 + 杜教筛。如果我们有 Min_25 筛呢?

我们发现 \(f(x) = \sigma_0(x^2)\) 满足 Min_25 筛的三个基本条件,\(f(p) = 3,f(p^k) = 2k + 1\) ,因此就是一道裸题了。

我们发现 SPOJ 还有两道题叫 DIVCNT3 / DIVCNTK。于是此题三倍经验……

代码

#include<bits/stdc++.h>
#define For(i,l,r) for(int i = (l),i##end = (r);i <= i##end;i++)
#define Fordown(i,r,l) for(int i = (r),i##end = (l);i >= i##end;i--)
#define debug(x) cout << #x << " = " << x << endlusing namespace std;typedef long long ll;
typedef unsigned long long ull;template <typename T> inline bool chkmin(T &x,T y) { return y < x ? x = y,1 : 0; }
template <typename T> inline bool chkmax(T &x,T y) { return x < y ? x = y,1 : 0; }const int INF = 0x3f3f3f3f;
const int N = 2e6 + 10;int prime[N],vis[N],id1[N],id2[N];
ull B[N],Ans[N];
ll val[N],n;
int pcnt = 0;inline ll read() {ll x = 0,flag = 1;char ch = getchar();while(!isdigit(ch) && ch != '-') ch = getchar();if(ch == '-') flag = -1,ch = getchar();while(isdigit(ch)) x = (x << 3) + (x << 1) + (ch - '0'),ch = getchar();return x * flag;
}inline void init(int Lim) {For(i,2,Lim) {if(!vis[i]) prime[++pcnt] = i;for(int j = 1;j <= pcnt && i * prime[j] <= Lim;j++) {vis[i * prime[j]] = true;if(i % prime[j] == 0) break;}}
}#define id(x) (x <= d ? id1[x] : id2[n / (x)])inline ull S(ll Lim,int cnt) {if(Lim <= 1 || prime[cnt] > Lim) return 0;int d = sqrt(n);ull ans = 3 * (B[id(Lim)] - (cnt - 1));for(int i = cnt;i <= pcnt && 1ll * prime[i] * prime[i] <= Lim;i++) {ll prod = prime[i];for(int times = 1;1ll * prod * prime[i] <= Lim;times++,prod = 1ll * prod * prime[i])ans += (2 * times + 1) * S(Lim / prod,i + 1) + (2 * times + 3);}return ans;
}inline void Calc(ll Lim) {int d = sqrt(Lim),cnt = 0;for(ll i = 1;i <= Lim;i = Lim / (Lim / i) + 1) {val[++cnt] = Lim / i,id(val[cnt]) = cnt;B[cnt] = val[cnt] - 1;}for(int i = 1;i <= pcnt && 1ll * prime[i] * prime[i] <= Lim;i++)for(int j = 1;j <= cnt && 1ll * prime[i] * prime[i] <= val[j];j++)B[j] = B[j] - B[id(val[j] / prime[i])] + (i - 1);
}int main() {
#ifndef ONLINE_JUDGEfreopen("DIVCNT2.in","r",stdin);freopen("DIVCNT2.out","w",stdout);
#endifint Case = read();init(2e6 + 5);while(Case--) {n = read();Calc(n);ull res = S(n,1) + 1;printf("%llu\n",res);}return 0;
}

Min_25 筛在一些质因子相关的问题上,也有很强的适用性,比如下面的这些题。

UOJ188 Sanrd

题意

\(f(x)\)\(x\) 的次大质因子,重复质因子算多个。求
\[ \sum_{i = l} ^ {r} f(i) \]
\(l,r \le 10^{11},TimeLimt = 5s\)

题解

这个函数显然不是积性函数了,但是这个次大质因子的形式,和 Min_25 筛枚举最小质因子的形式比较契合,因此可以想到在 Min_25 筛过程中统计答案。

考虑我们在递归计算 \(S\) 的过程中,假设当前递归到了 \(S(a,b)\) ,那么这些 \(\le a\)\(> P_b\) 的质数,在最开始的时候,一定是 \(P_{b - 1}\) 的倍数(具体原因可以仔细看看 \(S\) 的递归计算的式子)。所以这些数的次大质因子都是 \(P_{b - 1}\) 。因此就可以在 Min_25 筛过程中直接计算了。

LOJ572 Misaka Network 与求和

题意

\(f(x)\)\(x\) 的次大质因子,重复质因子算多个。求
\[ \sum_{i = 1}^{n}\sum_{j = 1}^{n}f(\gcd(i,j))^k \bmod 2^{32} \]
\(n,k \le 2 \times 10^9,TimeLimit = 4s\)

题解

前面经典的反演比较简单,式子可以转化为
\[ \sum_{T = 1}^{n} (\lfloor\frac{n}{T}\rfloor)^2 \sum_{d | T} f(d)^k \mu(\frac{T}{d}) \]
\(F(x) = f(x)^k\) ,则所求即为
\[ \sum_{T = 1}^{n} (\lfloor\frac{n}{T}\rfloor)^2 (F*\mu)(T) \]
于是我们只要能够快速求出 \(F * \mu\) 的前缀和,就可以整除分块了。我们设 \(\displaystyle S(n) = \sum_{i = 1}^{n} (F * \mu)(n)\),可以写出一个杜教筛的式子。
\[ g(1)S(n) = \sum_{i = 1}^n (F * \mu * g)(i) - \sum_{i = 2}^n g(i) S(\lfloor\frac{n}{i}\rfloor) \]
由于 \(\mu * 1 = \epsilon\) ,容易想到令 \(g = 1\) 。那么 \((F * \mu * g)(i) = (F * (\mu * g))(i) = (F * \epsilon)(i) = F(i)\)
\[ g(1)S(n) = \sum_{i = 1}^n F(i) - \sum_{i = 2}^n S(\lfloor\frac{n}{i}\rfloor) \]
对于 \(F(i)\) 的前缀和,直接套用 Min_25 筛即可。

转载于:https://www.cnblogs.com/ShichengXiao/p/10186064.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/265106.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【转】logback 常用配置详解(序)logback 简介

原创文章&#xff0c;转载请指明出处&#xff1a;http://aub.iteye.com/blog/1101222&#xff0c; 尊重他人即尊重自己 详细整理了logback常用配置&#xff0c; 不是官网手册的翻译版&#xff0c;而是使用总结&#xff0c;旨在更快更透彻的理解其配置 logback 常用配置详解&…

Linux curl 命令

curl is a tool to transfer data from or to a server, using one of the supported protocols ( http &#xff0c;https &#xff0c;ftp &#xff0c;telnet &#xff0c;...... ) [rootlocalhost ~]$ curl http://www.baidu.com/ # 获取指定页面&#xf…

vmware克隆Centos6.4虚拟机网卡无法启动问题

快速处理办法&#xff1a;cat /etc/sysconfig/network-scripts/ifcfg-eth0sed -i /UUID/d /etc/sysconfig/network-scripts/ifcfg-eth0sed -i /HWADDR/d /etc/sysconfig/network-scripts/ifcfg-eth0>/etc/udev/rules.d/70-persistent-net.rules rebootvmware克隆Centos6.4虚…

NXP(I.MX6uLL)DDR3实验——DDR3重要时间参数、时钟配置与原理图简析

目录DDR3 内存时间参数传输速率tRCD 参数CL 参数AL 参数tRC 参数tRAS 参数I.MX6U MMDC内存控制器简介MMDC内存控制器简介MMDC内存控制器信号引脚MMDC内存控制器时钟源ALPHA开发板核心板DDR3L原理图DDR3 内存时间参数 大家在购买DDR3 内存的时候通常会重点观察几个常用的时间参…

[elk]elasticsearch dsl语句

例子1 统计1&#xff0c;有唱歌兴趣的 2&#xff0c;按年龄分组 3&#xff0c;求每组平均年龄 4,按平均年龄降序排序 sql转为dsl例子 # 每种型号车的颜色数 > 1的 SELECT model,COUNT(DISTINCT color) color_count FROM cars GROUP BY model HAVING color_count > 1 ORDE…

编写atoi库函数

看到很多面试书和博客都提到编写atoi函数&#xff0c;在很多面试中面试官都会要求应聘者当场写出atoi函数的实现代码&#xff0c;但基本很少人能写的完全正确&#xff0c;倒不是这道题有多么高深的算法&#xff0c;有多么复杂的数据结构&#xff0c;只因为这道题要考虑的情况比…

NXP(I.MX6uLL)DDR3实验——DDR3初始化、校准、超频测试

DDR3L 初始化与测试ddr_stress_tester简介(DDR压力测试工具)DDR3L驱动配置DDR3L校准DDR3L超频测试DDR3L驱动总结ddr_stress_tester简介(DDR压力测试工具) NXP 提供了一个非常好用的DDR 初始化工具&#xff0c;叫做ddr_stress_tester。此工具已经放到了开发板光盘中&#xff0c…

Git 初识

Git是什么&#xff1f; Git(读音为/gɪt/。)是一个开源的分布式版本控制系统&#xff0c;可以有效、高速的处理从很小到非常大的项目版本管理。 Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。Torvalds 开始着手开发 Git 是为了作为一…

RGBLCD显示实验————复习到这

目录LCD 和eLCDIF 简介LCD 简介eLCDIF 接口硬件原理分析实验程序编写编译下载验证编写Makefile 和链接脚本编译下载LCD 液晶屏是常用到的外设&#xff0c;通过LCD 可以显示绚丽的图形、界面等&#xff0c;提高人机交互的效率。I.MX6U 提供了一个eLCDIF 接口用于连接RGB 接口的液…

std::shared_ptr

在std::shared_ptr被引入之前&#xff0c;C标准库中实现的用于管理资源的智能指针只有std::auto_ptr一个而已。std::auto_ptr的作用非常有限&#xff0c;因为它存在被管理资源的所有权转移问题。这导致多个std::auto_ptr类型的局部变量不能共享同一个资源&#xff0c;这个问题是…

unity 里调试native code

因项目需要&#xff0c;需要调试dll工程代码。 把生成的debug dll和pdb拷贝进unity的plugins工程&#xff0c;遇到 断点无法进入&#xff0c;修改下调试信息格式&#xff0c;OK。 转载于:https://www.cnblogs.com/marcher/p/10191521.html

将自己写的windows服务加入到windows集群中

最近发现windows集群能进行很多自定义&#xff0c;比如在集群中加入自己编写的服务。 能自定义的可不少&#xff0c;截个图&#xff1a; 本次演示中&#xff0c;只想用“通用服务”这个类型。 先列下步骤编写一个记录时间的Windows服务&#xff0c;这个服务会每隔1秒钟写入本地…

RTC实时时钟实验(低功耗、纽扣电池供电)

目录I.MX6U RTC 简介硬件原理分析实验程序编写修改文件MCIMX6Y2.h编写实验程序编译下载验证编写Makefile 和链接脚本编译下载实时时钟是很常用的一个外设&#xff0c;通过实时时钟我们就可以知道年、月、日和时间等信息。因此在需要记录时间的场合就需要实时时钟&#xff0c;可…

Python(21)_input用户交互

name input("请输入你的名字&#xff1a;") age input("请输入你的年龄&#xff1a;") print("我的名字是&#xff1a;"name" 年龄是&#xff1a;"age) #print(name) #print(age) 这是在本地调试的结果。因为程序是在远程服务器上执…

多点电容触摸屏实验

目录多点电容触摸简介硬件原理分析实验程序编写编译下载验证编写Makefile 和链接脚本编译下载随着智能手机的发展&#xff0c;电容触摸屏也得到了飞速的发展。相比电阻触摸屏&#xff0c;电容触摸屏有很多的优势&#xff0c;比如支持多点触控、不需要按压&#xff0c;只需要轻轻…

博客园自动添加版权说明,自动添加文章链接

功能&#xff1a; 1.给每一篇文章开头加上版权说明&#xff1b; 2.自动获取当前文章地址&#xff1b; 3.做了装饰。 将以下代码放在页首Html代码内即可&#xff1a; <script type"text/javascript"> var setMyBlog {setCopyright: function() {//设置版权信息…

如何添加地图控件到Windows Phone 8的页面中

原文 如何添加地图控件到Windows Phone 8的页面中 本主题介绍了各种方法来添加一个地图控件到Windows Phone 8的项目。该地图控件在Windows Phone的SDK 8.0的库的一部分。因为地图的控制是不是在内存中的核心控制&#xff0c;它必须被正确引用&#xff0c;然后才能使用它。您还…

LCD背光调节实验

目录LCD 背光调节简介硬件原理分析实验程序编写编译下载验证编写Makefile 和链接脚本编译下载不管是使用显示器还是手机&#xff0c;其屏幕背光都是可以调节的&#xff0c;通过调节背光就可以控制屏幕的亮度。在户外阳光强烈的时候可以通过调高背光来看清屏幕&#xff0c;在光线…

Mercurial(Hg)基本操作

Mercurial(Hg)基本操作 来源 https://www.cnblogs.com/gb2013/archive/2012/05/18/Mercurial_Basic.html Mercurial简介 Mercurial是一款非常优秀的分布式版本控制系统(DCVS)&#xff0c;具有高效率、跨平台、可扩展、使用简便且开源等优点&#xff0c;是目前最为流行的版本控制…

SPI实验

目录SPI & ICM-20608 简介SPI 简介SPI四线SPI四种工作模式SPI时序图I.MX6U ECSPI 简介ICM-20608 简介硬件原理分析实验程序编写编译下载验证编写Makefile 和链接脚本编译下载同I2C 一样&#xff0c;SPI 是很常用的通信接口&#xff0c;也可以通过SPI 来连接众多的传感器。相…