问题描述

  

  洲阁筛解决的问题主要是\(n\)范围较大的积性函数前缀和。

  

​  已知一积性函数\(f(i)\),求\(\sum_{i=1}^nf(i)\)。

  

  \(n\leq10^{12}\).

  

  

  

求解方法

  

  如果\(f(i)\)在质数处的取值比较简单,那么可以运用洲阁筛来求解。

  

​  我们需要两个辅助数组。

  

\(g_{i,j}\)

  

  定义如下:

\[\begin{aligned}
g_{i,j}&=\sum_{k=2}^i[k与p_1,p_2,...,p_j互质或就是其中某个质数]\; s(k)\\
&=\sum_{k=2}^i[k是\leq p_j的质数或k的最小质因子大于p_j]\; s(k)
\end{aligned}
\]

  其中\(s(x)\)是一个完全积性函数,它可以是\(s(x)=x\),或\(s(x)=1\),等等。

  

​  我们一般要求第二维计算到\(m\),其中\(m\)为满足\(p_m\le\sqrt n\)的最大正整数。

  

  这时候,\(g_{x,m}\)就表示函数\(s\)在前缀范围\([1,x]\)内的质数处的取值之和,这也是\(g\)数组的主要作用。但这里\(x\)的定义域不是\([1,n]\),下文会提到。

   

  这个数组怎么求呢?

  

​  首先边界条件比较简单:

\[g_{i,0}=\sum_{k=2}^is(k)
\]

  可是这里有一个限制:\(\sum_{k=2}^is(k)\)必须足够简单好算。如果函数前缀和比较复杂,如\(s=\mu\),就不能使用在\(s=\mu\)意义下计算\(g\)的这种方法。但是如果函数在质数的取值比较简单,如\(\mu(p)=-1\),我们可以考虑换一个角度:令\(s(x)=1\),可以计算出\([1,n]\)的质数个数\(p_{sum}\),那么我们可以用\(-1*p_{sum}\)表示所求的东西,一样达到了我们的目的(黑体字)。

  

  考虑由\(g_{i,j-1}\)推出\(g_{i,j}\)。

  

  若\(i<p_j^2\),显然\(g_{i,j}=g_{i,j-1}\)。

  

  否则当\(i\ge p_j^2\)时,如何考虑?\(g_{i,j-1}\)代表着一些在\(j-1\)时合法的数的函数值之和,而从\(j-1\)变成\(j\)时,若某些原本合法的数变得不合法,显然一定是因为触犯了第二个条件:最小质因子恰好为\(p_j\)。如何算出这一部分的数的函数值之和呢?

\[g_{i,j}=g_{i,j-1}-s(p_j)(g_{\lfloor\frac i {p_j}\rfloor,j-1}-g_{p_j-1,j-1})
\]

  

  

​  后面减去的部分就是这一部分数的函数值之和。首先它们都有一个最小质因子\(p_j\),随后,它们除去\(p_j\)剩下的部分,不可以含有小于\(p_j\)的质因子,因此剩下的部分至少大于等于\(p_j\),但要小于等于\(\frac{i}{p_j}\)。这恰好对应了\(g\)的定义!后面一部分算的就是

\[\sum_{k=p_j}^{\frac i {p_j}}[最小质因子>p_{j-1}]\; s(k)
\]

  但是\(n\)太大,存不下怎么办?

  

  记集合\(S=\{\lfloor\frac n x\rfloor |x\in[1,n]\}\;\;(\)\(|S|=2\sqrt n)\),我们只需要关注\(g_{i,...}\;\;(i\in S)\)即可,那为什么只用考虑第一维取这些值的情况呢?可以证明,所有以后需要调用的第一维都属于\(S\)。从\(g\)本身的递推需要来看,我们需要\(g_{\lfloor\frac i {p_j}\rfloor,j-1}\),它的第一维\(\lfloor \frac i {p_j}\rfloor\in S\);还需要\(g_{p_j-1,j-1}\),它的第一维\(p_j-1\le\sqrt n\),一定属于\(S\)。所以,其他的第一维取值就不需要计算了。从下文的\(h\)计算的调用来看,也都只会调用到\(S\)内的第一维,下文会提到。

  

  再之,我们发现每次递归时只用到第二维为\(j-1\)的数据,这给了我们滚动的思想:我们依次计算\(j=0...m\)的情况。将\(|S|\)个元素排成一排,分别表示在当前\(j\)意义下,\(g_{i,j},i\in S\)的取值。由于更新\(g_{i,j}\)的时候只需要用到诸如\(k\le i\)的\(g_{k,j-1}\),我们从大到小枚举并更新那些需要更新的元素\(i\in S,i\ge p_j^2\),这样可以保证调用的元素仍然是\(j-1\)意义下的;而\(i<p_j^2\)的情况,与\(j-1\)时完全没有改变,不需要操作,直接继承。

  

​  \(j\)越是大,我们需要更新的元素就越来越少。如此一层层地覆盖上去(很像一维背包的那种继承思想),我们,就可以计算到\(g_{n,m}\)了。这一步的复杂度是\(O(\frac {n^{\frac 3 4}}{\log n})\)。

  

  离散\(S\)中元素到数组上的方法很简单,对于\(x\in S\),如果\(x\le \sqrt n\),用\(pos_1[x]\)表示\(x\)的离散位置;如果\(x>\sqrt n\),用\(pos_2[\lfloor \frac n x\rfloor]\)表示\(x\)的离散位置。可以写一个简短的\(get()\)函数来处理询问离散位置的操作。

  

\(h_{i,j}\)

  

  定义如下:

\[h_{i,j}=\sum_{k=2}^i[k的最小质因子\ge p_j]\;f(k)
\]

  其递推式为:

\[\begin{aligned}
h_{i,j}&=\sum_{p_k\ge p_j}\sum_{e\ge 1且p_k^e\le i}f(p_k^e)h_{\lfloor \frac i{p_k^e}\rfloor,j+1}+f(p_k^e)\\
&=\sum_{p_k\ge p_j}\sum_{e\ge 1且p_k^e\le i}f(p_k^e)(h_{\lfloor \frac i{p_k^e}\rfloor,j+1}+1)
\end{aligned}
\]

  它相当于枚举所有在\([2,i]\)范围内,最小质因子大于等于\(p_j\)的数,并对函数值求和。首先枚举它们的最小质因数\(p_k\),再枚举最小质因数\(p_k\)的幂;最后统计有多少个数,满足除去\(p_k^e\)后剩余部分最小质因子大于\(p_j\),也就是大于等于\(p_{j+1}\),这和\(h\)本身的定义恰好符合。如此枚举,不会算重,但是会漏掉一种情况:\(f(p_k^e)\)没有被算入,因为\(h\)的\(\sum\)是从2开始枚举的。额外加上即可。

  

  我们使用搜索计算\(h\)。这里的搜索不需要记忆化,因为有结论是:如果要求不同的\(h_{i,j}\),它们在搜索时不会搜索到重复的地方。

  

  第一个循环不可以完全枚举\(k=j...m\),不然的话复杂度过高。当\(p_k^2>i\)时,余下的未计算的函数值之和恰好是函数在\(p\in(\sqrt i,i]\)处的取值之和,可以直接用\(g_{i,m}-g_{p_{m'},m}\)表示,其中\(m'\)为满足\(p_{m'}\le \sqrt i\)的最大正整数。我们发现\(p_m',i\in S\),回应上文,只需要计算\(g\)的第一维属于\(S\)时的情况。

  

  

  

答案计算

  

  \(\sum_{i=2}^nf(i)=h_{n,0}\)。

    

  那么\(\sum_{i=1}^nf(i)=h_{n,0}+f(1)\),简洁明了。

  

  当然,有时候题目甚至不需要调用\(h\)数组,这要依题目而灵活变化。

  

  

  

总结

  

  整体思路稍微有点复杂,但只要明白了洲阁筛对积性函数求和的关键步骤,就可以比较好地理解。

  

  首先,我们所讨论的积性函数,最好在质数处有简明的表达式。我们可以将表达式写出后,对于每个和式,用\(g\)在不同\(s(x)\)的意义下逐个求解。

  

  然后要理解洲阁筛对分配律的利用。它通过枚举最小质因数、枚举其作为最小质因数的指数、最后统计除去最小质因数后,剩余部分最小质因数大于自己的情况数这一种枚举方法,可以结合积性函数性质、运用\(h\)数组快速枚举遗漏的数,并得到其函数值之和。

  

  题目所求的问题并不会总是中规中矩,我们需要把题目求的表达式拆成一个一个部分,尽量用g或h的定义来表示,依次求解。

   

  总的时间复杂度为\(O(\frac{n^{\frac 3 4}}{\log n})\)。

  

  

  

代码

  

  以SPOJ的DivcntK为例,求的是\(\sum_{i=1}^n \sigma_0(i^k)\),\(n,k\le 10^{10}\)。这份代码是单组数据的。

  

  1. #include <cstdio>
  2. #include <cmath>
  3. #include <algorithm>
  4. #include <iostream>
  5. using namespace std;
  6. typedef long long ll;
  7. typedef unsigned long long ull;
  8. const int SQRTN=100005;
  9. bool vis[SQRTN];
  10. ll p[SQRTN],pcnt;
  11. ll n,k,sqrtn;
  12. int m;
  13. ll a[SQRTN*2],cnt;
  14. int pos1[SQRTN],pos2[SQRTN];
  15. ull g[SQRTN*2];
  16. void prework(){
  17. for(int i=2;i<SQRTN;i++){
  18. if(!vis[i])
  19. p[++pcnt]=i;
  20. for(int j=1;j<=pcnt&&i*p[j]<SQRTN;j++){
  21. int x=i*p[j];
  22. vis[x]=true;
  23. if(i%p[j]==0) break;
  24. }
  25. }
  26. }
  27. int gp(ll x){//getpos
  28. return x<=sqrtn?pos1[x]:pos2[n/x];
  29. }
  30. void Discretization(){
  31. for(ll i=1,j;i<=n;i=j+1){
  32. a[++cnt]=n/i;
  33. j=n/(n/i);
  34. }
  35. reverse(a+1,a+1+cnt);
  36. for(int i=1;i<=cnt;i++)
  37. if(a[i]<=sqrtn) pos1[a[i]]=i;
  38. else pos2[n/a[i]]=i;
  39. }
  40. void calc_g(){
  41. for(int i=1;i<=cnt;i++) g[i]=a[i]-1;
  42. for(int j=1;j<=m;j++)
  43. for(int i=cnt;i>=1&&a[i]>=p[j]*p[j];i--)
  44. g[i]-=g[gp(a[i]/p[j])]-g[gp(p[j]-1)];
  45. }
  46. ull calc_h(ll i,ll j){
  47. if(i<=1) return 0;
  48. ull res=0;
  49. int a;
  50. for(a=j;a<=m&&p[a]*p[a]<=i;a++)
  51. for(ll pe=p[a],e=1;pe<=i;pe*=p[a],e++)
  52. res+=(ull)(e*k+1)*(calc_h(i/pe,a+1)+1);
  53. if(p[a-1]<=i)
  54. res+=(ull)(k+1)*(g[gp(i)]-g[gp(p[a-1])]);
  55. return res;
  56. }
  57. int main(){
  58. prework();
  59. scanf("%lld%lld",&n,&k);
  60. sqrtn=(ll)sqrt(n);
  61. m=upper_bound(p+1,p+1+pcnt,sqrtn)-p-1;
  62. Discretization();
  63. calc_g();
  64. ull ans=(ull)(k+1)*(g[gp(n)]-m);
  65. for(int i=1;i<=m;i++)
  66. for(ll pe=p[i],e=1;pe<=n;pe*=p[i],e++)
  67. ans+=(ull)(e*k+1)*(calc_h(n/pe,i+1)+1);
  68. ans++;
  69. cout<<ans<<endl;
  70. return 0;
  71. }

【Learning】积性函数前缀和——洲阁筛(min_25写法)的更多相关文章

  1. A New Function(LightOJ 1098)积性函数前缀和的应用

    题意:要求对于1~n,每个数的约数(不包括1和其本身)的和. 题解:由于题目数据有2*10^9之大,因而不能直接暴力.需要考虑积性函数的特性,由于必定有重复的约数出现,因而可以对重复约数所在的区间进行 ...

  2. Mobius反演与积性函数前缀和演学习笔记 BZOJ 4176 Lucas的数论 SDOI 2015 约数个数和

    下文中所有讨论都在数论函数范围内开展. 数论函数指的是定义域为正整数域, 且值域为复数域的函数. 数论意义下的和式处理技巧 因子 \[ \sum_{d | n} a_d = \sum_{d | n} ...

  3. 洲阁筛 & min_25筛学习笔记

    洲阁筛 给定一个积性函数$F(n)$,求$\sum_{i = 1}^{n}F(n)$.并且$F(n)$满足在素数和素数次幂的时候易于计算. 显然有: $\sum_{i = 1}^{n} F(n) = ...

  4. 【learning】洲阁筛

    问题描述 快速求素数处点值比较好求的积性函数前缀和 大致过程 Step1.求出一定范围内的素数处点值之和(\(g\)) Step2.利用上面的\(g\)求出一个\(f\)然后用\(f\)求出前缀和 具 ...

  5. 【XSY3042】石像 拓扑排序 状压DP 洲阁筛

    题目大意 有 \(n\) 个整数 \(a_1,a_2,\ldots,a_n\),每个数的范围是 \([1,m]\).还有 \(k\) 个限制,每个限制 \(x_i,y_i\) 表示 \(a_{x_i} ...

  6. CF1097D Makoto and a Blackboard 积性函数、概率期望、DP

    传送门 比赛秒写完ABC结果不会D--最后C还fst了qwq 首先可以想到一个约数个数\(^2\)乘上\(K\)的暴力DP,但是显然会被卡 在\(10^{15}\)范围内因数最多的数是\(978217 ...

  7. 利用powerful number求积性函数前缀和

    好久没更博客了,先水一篇再说.其实这个做法应该算是杜教筛的一个拓展. powerful number的定义是每个质因子次数都 $\geq 2$ 的数.首先,$\leq n$ 的powerful num ...

  8. codeforces757E. Bash Plays with Functions(狄利克雷卷积 积性函数)

    http://codeforces.com/contest/757/problem/E 题意 Sol 非常骚的一道题 首先把给的式子化一下,设$u = d$,那么$v = n / d$ $$f_r(n ...

  9. powerful number求积性函数前缀和

    算法原理 本文参考了 zzq's blog . \(\text{powerful number}\) 的定义是每个质因子次数都 \(\ge 2\) 的数,有个结论是 \(\ge n\) 的 \(\te ...

随机推荐

  1. InnoDB表优化

    InnoDB表存储优化 适时的使用 OPTIMIZE TABLE 语句来重组表,压缩浪费的表空间.这是在其它优化技术不可用的情况下最直接的方法. OPTIMIZE TABLE 语句通过拷贝表数据并重建 ...

  2. shell中与运算 cut切分行 if while综合在一起的一个例子

    前言: 公司要统计 treasury库hive表磁盘空间,写了个脚本,如下: 查询hive仓库表占用hdfs文件大小: hadoop fs -du -h  /user/hive/warehouse/t ...

  3. Python 利用 BeautifulSoup 爬取网站获取新闻流

    0. 引言 介绍下 Python 用 Beautiful Soup 周期性爬取 xxx 网站获取新闻流: 图 1 项目介绍 1. 开发环境 Python: 3.6.3 BeautifulSoup:   ...

  4. 从零系列--开发npm包(二)

    一.利用shell简化组合命令 set -e CVERSION=$(git tag | ) echo "current version:$CVERSION" echo " ...

  5. Java non-javadoc

    Java注释 non-javadoc 表示该处没有自己的注释, @see javax.servlet.Servlet#init() 参考see后面的链接 /* * (non-javadoc) * @s ...

  6. 打包一个传统的ASP.NET web app作为Docker镜像

    (1)针对NerdDinner应用的Dockerfile内容如下 PS E:\DockeronWindows\Chapter02\ch02-nerd-dinner> cat .\Dockerfi ...

  7. MySQL基础练习(三)

    经过之前两次的学习,这次用MySQL进行略微复杂的操作练习 各部门工资最高的员工 首先创建表employee和表department.如下 我们需要查询每个部门工资最高的员工 select a.Nam ...

  8. MySQL基础练习(二)

    第一个例子我们编写一个 SQL 查询,列出所有超过或等于5名学生的课. 先建表 CREATE TABLE courses( student ) NOT NULL, class ) NOT NULL ) ...

  9. 第十一次ScrumMeeting博客

    第十一次ScrumMeeting博客 本次会议于11月29日(三)22时整在3公寓725房间召开,持续30分钟. 与会人员:刘畅.辛德泰张安澜.赵奕.方科栋. 1. 每个人的工作(有Issue的内容和 ...

  10. podSpec文件相关知识整理

    上一篇文章整理了我用SVN创建私有库的过程,本文将整理一下有关podSpec文件的相关知识. podSpec中spec的全称是“Specification”,说明书的意思.顾名思义,这是用来描述你这个 ...