用途
用于在 O(n23)的时间复杂度内求出 ∑ni=1f(i),其中 f为积性函数
原理
设 s(i)=∑ni=1f(i)
构造积性函数 g(i),设 f与 g的狄利克雷卷积为 f∗g
即:
(f∗g)(i)=∑d|ig(d)f(id)
对卷积得到的函数求前缀和:
n∑i=1(f∗g)(i)=n∑i=1∑d|ig(d)f(id)=n∑d=1g(d)∑d|if(id)=n∑d=1g(d)⌊nd⌋∑i=1f(i)=n∑d=1g(d)s(⌊nd⌋)
移一下项就有:
g(1)s(n)=n∑i=1(f∗g)(i)–n∑d=2g(d)s(⌊nd⌋)
很明显这个东西就能用记忆化搜索去求 s(n)了,后面那个 ∑nd=2g(d)s(⌊nd⌋)用数论分块就行了
这个构造的 g要求比较高,你需要让 ∑nd=2g(d)很好求,同时需要让 ∑ni=1(f∗g)(i)很好求这是个令人头疼的事情
复杂度
然而我不会算,所以千万别问我怎么算的
根据主定理:
T(n)=O(√n)+√n∑i=1T(i)+T(ni)=√n∑i=1O(√i)+O(√ni)=O(n34)
如果我们先用线性筛来预处理出 i∈[1,k]内的 s(i),那么记忆化搜索的复杂度为 O(n√k),预处理复杂度为 O(k),因此 k=n23时取到最优复杂度,为 O(n23)
实现
一般实现的时候用 map
来进行记忆化就行了,因为需要记忆化的元素个数为 n13,一般不会超过 104(否则 n23就已经超过 108的级别了),带个小 log问题不大
如果用哈希表应该会更快,但是没试过
当然也有更好的记忆化方法,就是对于 i记忆化 s(ni)的值,i的取值范围为 [1,n13]
这是因为你每次都会去搜当前的数字除以一个数向下取整
且 ⌊⌊na⌋b⌋=⌊nab⌋
还有当 i≤√n时有 ⌊n⌊ni⌋⌋=i
所以这样表示状态是不会出错的
例题
求欧拉函数 φ和莫比乌斯函数 μ的前缀和,n≤231–1
经典的杜教筛模板题
对于两者,都构造 g(i)=1
因为:
(φ∗g)(i)=i
(μ∗g)(i)=[i=1]
非常愉快
但这题似乎有点卡常(BZOJ 算的是总时限另当别论),有这么几个优化技巧:
- 尽量
unsigned int
存,避免long long
- μ的前缀和用
int
存 - 不需要进行两次记忆化搜索,因为两棵 dfs 树是一模一样的,在同一个 dfs 里同时计算两个函数值就行了
- 由于有多组询问,可以适当地增大预处理的数据量
代码:
0 条评论