最近突然做到一些求积性函数前缀和的题,用到了各种筛,有一题用到 min_25 筛法,于是好好学习了一波,运用极不熟练。后来又遇到一道杜教筛的题,结果发现自己连 phi(x) 前缀和都不会推了?吓得我赶紧复习 + 写博客。
前置技能
常见(完全)积性函数;整除分块; dirichlet 卷积;埃氏筛
这里还是简单介绍一下 dirichlet 卷积:
我们用 * 表示两个函数的 dirichlet 卷积。
定义函数 f 和 g 的 dirichlet 卷积形式为 $(f*g)(n)=\sum_{d|n} f(d)g\left (\frac{n}{d}\right )$ 。
接下来,设 $f$ 为积性函数,我们要求 $\sum_{i=1}^{n} f(i)$ , n 是 $10^9\sim 10^{12}$ 左右的级别。本文忽略复杂度分析(需用到积分相关知识,本人太弱不会)。
杜教筛
(先扔链接:https://www.cnblogs.com/zzqsblog/p/5461392.html)
适用范围:存在另两个积性函数 $g,h$ ,且满足 $f*g=h$ , $g,h$ 函数的前缀和比较容易求。
先来举几个例子:
- 比如说要求 $\mu$ 的前缀和,我们知道 $\mu * 1=e$ ( $e(i)=[i=1]$ ), $e$ 的前缀和显然恒为 $[n\ge 1]$ , $1$ 的前缀和也很好求,所以可以使用杜教筛;
- 又比如说要求 $\varphi$ 的前缀和,我们知道 $\varphi * 1=id$ , $1,id$ 的前缀和都很好求 ,所以也可以使用杜教筛。
那么具体怎么求呢?
设 $S(n)=\sum_{i=1}^{n} f(i)$ ,那么有
$$\begin{aligned} \sum_{i=1}^{n} (f*g)(i) &= \sum_{i=1}^{n} \sum_{d|i} f(d)g\left (\frac{i}{d} \right ) \\ S(n)=\sum_{i=1}^n f(i) &= \sum_{i=1}^{n} (f*g)(i) - \sum_{i=1}^{n} \sum_{d|i,d<i} f(d)g\left (\frac{i}{d}\right ) \\ &=\sum_{i=1}^n (f*g)(i) - \sum_{i=2}^n g(i) \sum_{d=1}^{\left \lfloor \frac{n}{i} \right\rfloor} f(d)\\ &=\sum_{i=1}^n (f*g)(i) - \sum_{i=2}^n g(i)S\left (\left \lfloor \frac{n}{i} \right \rfloor \right ) \end{aligned}$$
可以发现我们得到了一个 $S(n)$ 的子问题,可以递归下去求解。
至于边界情况,考虑如果 $n\leq B$ 的时候我们直接用线性筛线性求解 $S(n)$ ,当 B 取 $n^{\frac 23}$ 的时候复杂度最优,大概为 $\mathcal{O}(n^{\frac23})$ 。足以解决这个问题。
贴代码 (一百年前写的)
1 #include<bits/stdc++.h> 2 #define rep(i,x,y) for (int i=(x);i<=(y);i++) 3 #define ll long long 4 using namespace std; 5 const int N=1e6+5; 6 int p[N/10],cnt,vis[N],mu[N]; map<ll,ll> mp; 7 void init(int n){ 8 mu[1]=1; 9 rep (i,2,n){ 10 if (!vis[i]) p[++cnt]=i,mu[i]=-1; 11 for (int j=1;j<=cnt&&i*p[j]<=n;j++){ 12 vis[i*p[j]]=1; 13 if (i%p[j]==0) break; 14 mu[i*p[j]]=-mu[i]; 15 } 16 } 17 rep (i,2,n) mu[i]+=mu[i-1]; 18 } 19 ll S(ll n){ 20 if (n<N) return mu[n]; 21 if (mp.count(n)) return mp[n]; 22 ll ret=1; 23 for (ll i=2,last;i<=n;i=last+1){ 24 last=n/(n/i); 25 ret-=(last-i+1)*S(n/i); 26 } 27 return mp[n]=ret; 28 } 29 int main(){ 30 init(N-1); 31 ll a,b; cin>>a>>b; cout<<S(b)-S(a-1); 32 return 0; 33 }