杜教筛

先来一道水题

求Σi=1nμ(i)

n<=1e5 我会暴力!!

n<=1e7我会线性筛!!

n<=1e9我……WCNM!!

众所周知,线性筛它死了

这个时候,我们的杜教筛大哥走了过来,说:让我来!

杜教筛是干什么用的呢?是用来求积性函数前缀和的

时间复杂度O(n^(2/3))
我们假设有一个积性函数f

设Σi=1nf(i)=s(i)

设f*g=h,f,g,h是积性函数

考虑Σi=1nh(i)

Σi=1nh(i)=Σi=1nΣd|ig(d)*f(i/d)

更换枚举顺序,Σi=1nh(i)=Σd=1ng(d)*Σd|inf(i/d)

设i'=i/d,i=i'*d

则原式可化为Σi=1nh(i)=Σd=1ng(d)*Σi'=1⌊n/d⌋f(i')

后面那个Σ=s(⌊n/d⌋)

所以原式可化为Σi=1nh(i)=Σd=1ng(d)*s(⌊n/d⌋)

将右边第一项提出来,Σi=1nh(i)=Σd=2ng(d)*s(⌊n/d⌋)+g(1)*s(n)

所以,g(1)*s(n)=Σi=1nh(i)-Σd=2ng(d)*s(⌊n/d⌋)

如果Σi=1nh(i)可以O(1)求的话,右边数论分块再加上记忆搜,是可以很快求出答案的

具体的话,如果用线性筛筛出来前n2/3个之后,再用上式带入计算,总时间复杂度就是O(n2/3)不会证233

我们知道,记忆化是要开数组的,显然n<=1e9它不让你开数组,那怎么办呢??

方法1:我会哈希!!那你比较勤劳

方法2:我会map!!那你多个log

可是当你遇到了像david-alwal这样既不勤劳又不想要log的人怎么办呢

方法3:我们有黑科技unordered_map!!

关于unordered_map的几点注意事项:

1、万能库----bits/stdc++.h----它死了!!!@Th_Au_K
我们需要开一个库,#include<tr1/unordered_map>


2、声明变量的时候,tr1::unordered_map<int,int>M;

剩下它就和map一样了,除了复杂度,它少了一个log

举几个晓栗子

eg1:f=μ

因为μ*I=e

e的前缀和极其好求就是1,所以g=I,h=e就好了

eg2:f=φ

因为φ*I=id

id的前缀和是n*(n+1)/2

所以g=I,h=id

eg3:f(n)=n*φ(n)

不那么显然了

h=f*g

那么,h(n)=(f*g)(n)=Σd|nf(d)*g(n/d)=Σd|nφ(d)*d*g(n/d)

那个d很不爽,所以我们考虑g=id

那么,原式=Σd|nφ(d)*d*n/d=Σd|nφ(d)*n

将n提出去,原式=n*Σd|nφ(d)=n2

即f(n)=n*φ(n),g(n)=n,h(n)=n2即可

posted @ 2019-06-26 15:51  david_alwal  阅读(303)  评论(2编辑  收藏  举报