前置知识:狄利克雷卷积
杜教筛是快速求某些积性函数的前缀和的一种方法,时间复杂度一般能达到 O ( n 2 3 ) O(n^{\frac 23}) O(n32)。
设 f , g f,g f,g为积性函数, F , G F,G F,G分别是 f , g f,g f,g的前缀和。 h h h为 f , g f,g f,g的狄利克雷卷积, H H H为 h h h的前缀和。我们要求 F F F,但 F F F不好求,而 G , H G,H G,H比较好求,我们可以通过 G , H G,H G,H得到 F F F的递推式,再利用数论分块加速,快速求出 F F F。
f ∗ g = h f*g=h f∗g=h
h ( n ) = ∑ d ∣ n f ( d ) × g ( n d ) = f ( n ) × g ( 1 ) + ∑ d ∣ n , d < n f ( d ) × g ( n d ) h(n)=\sum\limits_{d|n}f(d)\times g(\dfrac nd)=f(n)\times g(1)+\sum\limits_{d|n,d
∑ i = 1 n h ( i ) = ∑ i = 1 n f ( i ) × g ( 1 ) + ∑ i = 1 n ∑ d ∣ i , d < i f ( d ) × g ( i d ) \sum\limits_{i=1}^n h(i)=\sum\limits_{i=1}^n f(i)\times g(1)+\sum\limits_{i=1}^n\sum\limits_{d|i,di=1∑nh(i)=i=1∑nf(i)×g(1)+i=1∑nd∣i,d<i∑f(d)×g(di)
令 j = i d j=\dfrac id j=di,因为 g g g为积性函数, g ( 1 ) × g ( p ) = g ( p ) g(1)\times g(p)=g(p) g(1)×g(p)=g(p),所以 g ( 1 ) = 1 g(1)=1 g(1)=1
H ( n ) = F ( n ) + ∑ j = 2 n g ( j ) ∑ d = 1 n j f ( d ) = F ( n ) + ∑ j = 2 n g ( j ) F ( n j ) H(n)=F(n)+\sum\limits_{j=2}^ng(j)\sum\limits_{d=1}^{\frac nj}f(d)=F(n)+\sum\limits_{j=2}^ng(j)F(\dfrac nj) H(n)=F(n)+j=2∑ng(j)d=1∑jnf(d)=F(n)+j=2∑ng(j)F(jn)
F ( n ) = H ( n ) − ∑ j = 2 n g ( j ) F ( n j ) F(n)=H(n)-\sum\limits_{j=2}^ng(j)F(\dfrac nj) F(n)=H(n)−j=2∑ng(j)F(jn)
若我们预处理出 f f f的前 m m m项,则时间复杂度为 O ( m + n m ) O(m+\dfrac{n}{\sqrt m}) O(m+mn)。
当 m = n 2 3 m=n^{\frac 23} m=n32时时间复杂度最小,为 O ( n 2 3 ) O(n^{\frac 23}) O(n32)。
P4213 【模板】杜教筛
求 ∑ i = 1 n ϕ ( i ) \sum\limits_{i=1}^n\phi(i) i=1∑nϕ(i)和 ∑ i = 1 n μ ( i ) \sum\limits_{i=1}^n \mu(i) i=1∑nμ(i),其中 1 ≤ n ≤ 1 0 9 1\leq n\leq 10^9 1≤n≤109。
先求 ∑ i = 1 n ϕ ( i ) \sum\limits_{i=1}^n\phi(i) i=1∑nϕ(i),我们知道 ϕ ∗ I = I d \phi*I=Id ϕ∗I=Id
I d ( n ) = ∑ d ∣ n ϕ ( d ) × I ( n d ) = ϕ ( n ) + ∑ d ∣ n , d > 1 I ( d ) × ϕ ( n d ) Id(n)=\sum\limits_{d|n}\phi(d)\times I(\dfrac nd)=\phi(n)+\sum\limits_{d|n,d>1}I(d)\times \phi(\dfrac nd) Id(n)=d∣n∑ϕ(d)×I(dn)=ϕ(n)+d∣n,d>1∑I(d)×ϕ(dn)
分别求前缀和,得
n ( n + 1 ) 2 = ∑ i = 1 n ϕ ( i ) + ∑ i = 1 n ∑ d ∣ i , d > 1 I ( d ) × ϕ ( i d ) \dfrac{n(n+1)}{2}=\sum\limits_{i=1}^n\phi(i)+\sum\limits_{i=1}^n\sum\limits_{d|i,d>1}I(d)\times \phi(\dfrac id) 2n(n+1)=i=1∑nϕ(i)+i=1∑nd∣i,d>1∑I(d)×ϕ(di)
∑ i = 1 n ϕ ( i ) = n ( n + 1 ) 2 − ∑ d = 2 n I ( d ) ∑ i = 1 ⌊ n d ⌋ ϕ ( i ) \sum\limits_{i=1}^n\phi(i)=\dfrac{n(n+1)}{2}-\sum\limits_{d=2}^nI(d)\sum\limits_{i=1}^{\lfloor \frac nd\rfloor}\phi(i) i=1∑nϕ(i)=2n(n+1)−d=2∑nI(d)i=1∑⌊dn⌋ϕ(i)
设 f ( n ) = ∑ i = 1 n ϕ ( i ) f(n)=\sum\limits_{i=1}^n\phi(i) f(n)=i=1∑nϕ(i),则上式变为
f ( n ) = n ( n + 1 ) 2 − ∑ i = 2 n I ( d ) × f ( ⌊ n d ⌋ ) f(n)=\dfrac{n(n+1)}{2}-\sum\limits_{i=2}^nI(d)\times f(\lfloor \dfrac nd\rfloor) f(n)=2n(n+1)−i=2∑nI(d)×f(⌊dn⌋)
预处理出前 n 2 3 n^{\frac 23} n32个 f f f值,则时间复杂度为 O ( n 2 3 ) O(n^{\frac 23}) O(n32)。
再来求 ∑ i = 1 n μ ( i ) \sum\limits_{i=1}^n\mu(i) i=1∑nμ(i),我们知道 μ ∗ I = ϵ \mu*I=\epsilon μ∗I=ϵ
ϵ ( n ) = ∑ d ∣ n μ ( d ) × I ( n d ) = μ ( n ) × I ( 1 ) + ∑ d ∣ n , d < n μ ( d ) × I ( n d ) \epsilon(n)=\sum\limits_{d|n}\mu(d)\times I(\dfrac nd)=\mu(n)\times I(1)+\sum\limits_{d|n,d
分别求前缀和,得
1 = ∑ i = 1 n μ ( i ) + ∑ i = 1 n ∑ d ∣ i , d > 1 I ( d ) × μ ( i d ) = f ( n ) + ∑ d = 2 n I ( d ) ∑ i = 1 ⌊ n d ⌋ μ ( i ) 1=\sum\limits_{i=1}^n\mu(i)+\sum\limits_{i=1}^n \sum\limits_{d|i,d>1}I(d)\times \mu(\dfrac id)=f(n)+\sum\limits_{d=2}^nI(d)\sum\limits_{i=1}^{\lfloor \frac nd\rfloor}\mu(i) 1=i=1∑nμ(i)+i=1∑nd∣i,d>1∑I(d)×μ(di)=f(n)+d=2∑nI(d)i=1∑⌊dn⌋μ(i)
设 f ( n ) = ∑ i = 1 n μ ( i ) f(n)=\sum\limits_{i=1}^n\mu(i) f(n)=i=1∑nμ(i),则
1 = f ( n ) + ∑ d = 2 n I ( d ) × f ( ⌊ n d ⌋ ) 1=f(n)+\sum\limits_{d=2}^nI(d)\times f(\lfloor \dfrac nd\rfloor) 1=f(n)+d=2∑nI(d)×f(⌊dn⌋)
f ( n ) = 1 − ∑ d = 2 n I ( d ) × f ( ⌊ n d ⌋ ) f(n)=1-\sum\limits_{d=2}^nI(d)\times f(\lfloor \dfrac nd\rfloor) f(n)=1−d=2∑nI(d)×f(⌊dn⌋)
同样可以用 O ( n 2 3 ) O(n^{\frac 23}) O(n32)的时间复杂度解决。
#include
using namespace std;
const int N=5000000;
int z[N+5],p[N+5],mu[N+5];
long long ph[N+5],sph[N+5],smu[N+5];
map<long long,long long>mph,mmu;
void init(){
mu[1]=ph[1]=1;
for(int i=2;i<=N;i++){
if(!z[i]){
p[++p[0]]=i;mu[i]=-1;ph[i]=i-1;
}
for(int j=1;j<=p[0]&&i*p[j]<=N;j++){
z[i*p[j]]=1;
if(i%p[j]==0){
mu[i*p[j]]=0;
ph[i*p[j]]=ph[i]*p[j];
break;
}
mu[i*p[j]]=-mu[i];
ph[i*p[j]]=ph[i]*(p[j]-1);
}
}
for(int i=1;i<=N;i++){
sph[i]=sph[i-1]+ph[i];
smu[i]=smu[i-1]+mu[i];
}
}
long long gt1(int t){
if(t<=N) return sph[t];
if(mph.count(t)) return mph[t];
long long re=0;
for(int l=2,r;l<=t;l=r+1){
if(t/l==1) r=t;
else r=t/(t/l);
re+=gt1(t/l)*(r-l+1);
if(r==t) break;
}
return mph[t]=t*(t+1ll)/2-re;
}
long long gt2(int t){
if(t<=N) return smu[t];
if(mmu.count(t)) return mmu[t];
long long re=0;
for(int l=2,r;l<=t;l=r+1){
if(t/l==1) r=t;
else r=t/(t/l);
re+=gt2(t/l)*(r-l+1);
if(r==t) break;
}
return mmu[t]=1-re;
}
int main()
{
int t,n;
init();
scanf("%d",&t);
while(t--){
scanf("%d",&n);
printf("%lld %lld\n",gt1(n),gt2(n));
}
return 0;
}