问题描述

  

  洲阁筛解决的问题主要是\(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}\)。这份代码是单组数据的。

  

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int SQRTN=100005;
bool vis[SQRTN];
ll p[SQRTN],pcnt;
ll n,k,sqrtn;
int m;
ll a[SQRTN*2],cnt;
int pos1[SQRTN],pos2[SQRTN];
ull g[SQRTN*2];
void prework(){
for(int i=2;i<SQRTN;i++){
if(!vis[i])
p[++pcnt]=i;
for(int j=1;j<=pcnt&&i*p[j]<SQRTN;j++){
int x=i*p[j];
vis[x]=true;
if(i%p[j]==0) break;
}
}
}
int gp(ll x){//getpos
return x<=sqrtn?pos1[x]:pos2[n/x];
}
void Discretization(){
for(ll i=1,j;i<=n;i=j+1){
a[++cnt]=n/i;
j=n/(n/i);
}
reverse(a+1,a+1+cnt);
for(int i=1;i<=cnt;i++)
if(a[i]<=sqrtn) pos1[a[i]]=i;
else pos2[n/a[i]]=i;
}
void calc_g(){
for(int i=1;i<=cnt;i++) g[i]=a[i]-1;
for(int j=1;j<=m;j++)
for(int i=cnt;i>=1&&a[i]>=p[j]*p[j];i--)
g[i]-=g[gp(a[i]/p[j])]-g[gp(p[j]-1)];
}
ull calc_h(ll i,ll j){
if(i<=1) return 0;
ull res=0;
int a;
for(a=j;a<=m&&p[a]*p[a]<=i;a++)
for(ll pe=p[a],e=1;pe<=i;pe*=p[a],e++)
res+=(ull)(e*k+1)*(calc_h(i/pe,a+1)+1);
if(p[a-1]<=i)
res+=(ull)(k+1)*(g[gp(i)]-g[gp(p[a-1])]);
return res;
}
int main(){
prework();
scanf("%lld%lld",&n,&k);
sqrtn=(ll)sqrt(n);
m=upper_bound(p+1,p+1+pcnt,sqrtn)-p-1;
Discretization();
calc_g();
ull ans=(ull)(k+1)*(g[gp(n)]-m);
for(int i=1;i<=m;i++)
for(ll pe=p[i],e=1;pe<=n;pe*=p[i],e++)
ans+=(ull)(e*k+1)*(calc_h(n/pe,i+1)+1);
ans++;
cout<<ans<<endl;
return 0;
}

【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. java四种访问权限修饰符

    java中四个访问权限修饰符: public(公开的).protected(受保护的).default(默认的).private(私有的). 它们决定了紧跟其后被定义的东西的使用范围. 适用范围< ...

  2. 【翻译】HOG, Histogram of Oriented Gradients / 方向梯度直方图 介绍

    本文翻译自 SATYA MALLICK 的 "Histogram of Oriented Gradients" 原文链接: https://www.learnopencv.com/ ...

  3. GitHub笔记(五)——忽略文件、配置别名、搭建服务器

    六.忽略文件 忽略某些文件时,需要编写.gitignore: .gitignore文件本身要放到版本库里,并且可以对.gitignore做版本管理! 忽略文件的原则是: 忽略操作系统自动生成的文件,比 ...

  4. Linear Regression and Maximum Likelihood Estimation

    Imagination is an outcome of what you learned. If you can imagine the world, that means you have lea ...

  5. thinkphp 3.x下的任意文件包含(有条件)分析

    漏洞原理 实现自己的模版引擎不当,在模版渲染的情况下存在任意变量覆盖漏洞.. 漏洞详情 漏洞位置1 ThinkPHP/Library/Think/View.class.php 需要修改配置文件 指定T ...

  6. whoami,who,w命令详解

    http://www.voidcn.com/blog/wszzdanm/article/p-6145895.html 命令功能:显示登录用户的信息 命令格式: 常用选项: 举例: w 显示已经登录的用 ...

  7. [java] jar file

    查看 .jar 内的文件 jar tf jarfile.jar maven 项目中, java 读取目标文件 运行 mvn package 打包项目是, src/main/resources 下的文件 ...

  8. caffe 预训练 或者Fine-Tuning 操作

    1.使用预训练模型,需要修改训练的prototxt,将layer name改为与要使用模型的layer name相同即可. Borrowing Weights from a Pretrained Ne ...

  9. roadhog中如何拷贝文件

    一:使用 public 目录 我们约定 public 目录下的文件会在 server 和 build 时被自动 copy 到输出目录(默认是 ./dist)下.所以可以在这里存放 favicon, i ...

  10. 关于react虚拟DOM的研究

    1.传统的前端是这样的,我在学校也都是这样做的,html(jsp)主要负责提供所有的DOM节点,而javascript负责动态效果,比如按钮点击,图片轮播等,这样的话javascript如何组织结构是 ...