最近突然做到一些求积性函数前缀和的题,用到了各种筛,有一题用到 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 }
51nod1244 莫比乌斯函数之和

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-11-13
  • 2021-08-22
  • 2021-10-29
  • 2021-06-01
猜你喜欢
  • 2022-12-23
  • 2021-07-31
  • 2021-11-30
  • 2022-12-23
  • 2021-07-23
  • 2022-12-23
  • 2021-11-13
相关资源
相似解决方案