一些定义
- 数论函数:定义域为正整数的函数。
- 积性函数:满足(f(a)f(b)=f(ab) (gcd(a,b)=1))的数论函数。
- 积性筛:在低于线性的时间内求出积性函数前缀和的奇妙算法。
一些积性函数
- (varphi(x)):欧拉函数。
- (mu(x)):莫比乌斯函数。
- (epsilon(x)):元函数。(epsilon(x)=delta_{x1})。
- (d(x)):约数函数。(d(x)=sum_{d|x}1)。
- (sigma(x)):约数和函数。(sigma(x)=sum_{d|x}d)。
- (I(x)):恒等函数。(I(x)=1)。
- (id(x)):单位函数。(id(x)=x)。
狄利克雷卷积
- 两个数论函数(f(x),g(x))的狄利克雷卷积定义为:(f*g=sum_{d|n}f(d)g(frac nd))。
- 显然,狄利克雷卷积满足交换律、结合律、分配律。并且我们不难发现一个性质:两个积性函数的狄利克雷卷积依然是积性函数。
杜教筛
算法流程
- 设(S(n)=sum_{i=1}^n f(i))。我们要求一个(S(n))。
- 设有另一个积性函数(g),并设(h=f*g),则有:
[sum_{i=1}^nh(i)=sum_{i=1}^nsum_{d|i}f(d)g(frac id)=sum_{d=1}^ng(d)sum_{i=1}^{lfloorfrac nd
floor}f(i)=sum_{d=1}^ng(d)S(lfloorfrac nd
floor)
]
- 因此,(g(1)S(n)=sum_{i=1}^nh(i)-sum_{d=2}^ng(d)S(lfloorfrac nd floor))。
- 由于(g)是积性函数,(g(1)=1),所以(S(n))就等于右式。
- 对于(sum h(i)),我们要有一个快速求它的算法(一般要求时间不超(O(sqrt n)));而对于被减数,我们可以先分块,然后递归求解(S(lfloorfrac nd floor))。由于(lfloorfrac {lfloorfrac ab floor}c floor=lfloorfrac a{bc} floor),我们算过的(S(x))一定满足(x=lfloorfrac nd floor(din[1,n])),故可以用两个桶(一个是(≤sqrt n)的,一个是(>sqrt n)的,当然也可以合成一个桶)记忆化一下。
- 空间复杂度显然(O(sqrt n))。
- 时间的话,可以发现(x=lfloorfrac nd floor(din[1,n]))只有(O(sqrt n))种取值,而且它们都是算过一次就不再算了(记忆化)。因此,(T(n)=sum_{i=1}^{sqrt n}O(sqrt i)+O(sqrt{lfloorfrac ni floor}))。可以求一个定积分,便知(T(n)=O(n^{frac 34}))。
- 如果先用线筛预处理出前(n^{frac 23})项,剩余部分的时间复杂度为(O(int_0^{n^{frac 13}}sqrt{frac nx}dx)=O(n^{frac 23}))。
简单例题
T1
- 求(S(n)=sum_{i=1}^nmu(i))。
- 我们知道(mu)有个性质:(mu*I=epsilon)。那么直接套公式便可得:(S(n)=1-sum_{d=2}^nS(lfloorfrac nd floor))。
T2
- 定义(f(n)=nvarphi(n)),求(S(n)=sum_{i=1}^nf(i))。
- 设(h=f*id),可知(h(n)=sum_{d|n}nvarphi(d)=n^2)。则:(S(n)=frac{n(n+1)(2n+1)}6-sum_{d=2}^ndS(lfloorfrac nd floor))。
T3:51nod2026
- 题目其实是要求((S(n)=sum_{i=1}^nf(i))^2)。
- 稍微推一下式子,(S(n)=sum_{i=1}^nsum_{d|i}dmu(d)=sum_{d=1}^ndmu(d)lfloorfrac nd floor)。后面(lfloorfrac nd floor)可以分块来处理,现在我们要处理的只是若干个(s(x)=sum_{d=1}^xdmu(d))而已(而且这些(x)也都是(n)整除某一个数得来)。
- 依然让它卷上(id),(h(n)=sum_{d|n}nmu(d)=epsilon(n))。则:(s(n)=1-sum_{d=2}^ndS(lfloorfrac nd floor))。
#include <cmath>
#include <cstdio>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int M=1e5,N=2e5,mo=1e9+7;
int n,k,s[N],S;
bool v[N];
int C(int x) {return x<=k?M+x:n/x;}
int P(int&x,int y) {x=(1ll*x+y)%mo;}
void gets(int x)
{
v[C(x)]=s[C(x)]=1;
for(int i,l=2,r; l<=x; l=r+1)
{
r=x/(i=x/l);
if(!v[C(i)]) gets(i);
P(s[C(x)],mo-1ll*(l+r)*(r-l+1)/2%mo*s[C(i)]%mo);
}
}
int main()
{
scanf("%d",&n), k=sqrt(n);
gets(n);
for(int i,l=1,r; l<=n; l=r+1)
{
r=n/(i=n/l);
P(S,1ll*i*(1ll*mo+s[C(r)]-s[C(l-1)])%mo);
}
printf("%lld",1ll*S*S%mo);
}
Min_25筛
前言
- 16年rzz在集训队论文里发明了个洲阁筛,它可以在(O(frac{n^{frac 34}}{log n}))的时间内筛出个性质较难发现的积性函数的前缀和。
- 不过zzt觉得它又臭又长,于是在18年集训队论文里引进了Min_25发明的Min_25筛。
- 据说是洲阁筛的精简版。
算法简介
- 首先我们须保证(f(p^c))((p)是质数)可以快速计算。我们要求(F(n)=sum_{i=1}^nf(i))。
- 记(p_k)为第(k)小的质数。设(lpf(n))为(n)的最小质因数,(n=1)时其值为1;(F_k(n)=sum_{i=2}^n[p_k≤lpf(i)]f(i))。则可得:
- 现在考虑计算(F_{prime}(n)=sum_{2≤p≤n})。
- 设(G_k(n)=sum_{i=2}^n[p_k<lpf(i)lor isprime(i)]f(i)),即埃氏筛筛完k轮后剩下数的和,则显然(F_{prime}=G_{sqrt n})。记(G_0=sum_{i=2}^nf(i))。
- 转移即为: