(杜教筛)P4213 【模板】杜教筛(Sum)

Label

杜教筛模板题

Description

T ( T ≤ 10 ) T(T\le 10) T(T10)组数据,每组数据包含一个正整数 n ( n < 2 31 ) n(n<2^{31}) n(n<231),求 ∑ i = 1 n φ ( i ) \sum_{i=1}^{n}\varphi(i) i=1nφ(i) ∑ i = 1 n μ ( i ) \sum_{i=1}^{n}\mu(i) i=1nμ(i)

Solution

杜教筛

杜教筛一般用于处理数论函数前缀和的问题。杜教筛的基本思想是:对于求解某个数论函数 f ( n ) f(n) f(n)前缀和(而非一个线性表) S ( n ) = ∑ i = 1 n f ( i ) S(n)=\sum_{i=1}^{n}f(i) S(n)=i=1nf(i),我们设法构造一个 S ( n ) S(n) S(n)关于 S ( ⌊ n i ⌋ ) S(\lfloor\frac{n}{i}\rfloor) S(in)的递推式。

引理:对于任意两个数论函数 f , g f,g f,g,设 S ( n ) = ∑ i = 1 n f ( i ) S(n)=\sum_{i=1}^{n}f(i) S(n)=i=1nf(i),则必有:

∑ i = 1 n ( f ∗ g ) ( i ) = ∑ i = 1 n g ( i ) S ( ⌊ n i ⌋ ) \sum_{i=1}^{n}(f*g)(i)=\sum_{i=1}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor) i=1n(fg)(i)=i=1ng(i)S(in)

证明:按照P3327题解注释(2)(3)的方法,我们不难得到:

∑ i = 1 n ( f ∗ g ) ( i ) \sum_{i=1}^{n}(f*g)(i) i=1n(fg)(i)

= ∑ i = 1 n ∑ d ∣ i g ( d ) f ( i d ) =\sum_{i=1}^{n}\sum_{d|i}g(d)f(\frac{i}{d}) =i=1ndig(d)f(di)

= ∑ d = 1 n g ( d ) ∑ i = 1 n [ d ∣ i ] f ( i d ) =\sum_{d=1}^{n}g(d)\sum_{i=1}^{n}[d|i]f(\frac{i}{d}) =d=1ng(d)i=1n[di]f(di)

= ∑ d = 1 n g ( d ) ∑ i = 1 n [ 1 ∣ i d ] f ( i d ) =\sum_{d=1}^{n}g(d)\sum_{i=1}^{n}[1|\frac{i}{d}]f(\frac{i}{d}) =d=1ng(d)i=1n[1di]f(di)

= ∑ d = 1 n g ( d ) ∑ i = 1 ⌊ n d ⌋ f ( i ) =\sum_{d=1}^{n}g(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}f(i) =d=1ng(d)i=1dnf(i)

= ∑ i = 1 n g ( i ) S ( ⌊ n i ⌋ ) , □ =\sum_{i=1}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor),\square =i=1ng(i)S(in),

将引理 ∑ i = 1 n ∑ d ∣ i ( f ∗ g ) ( i ) = ∑ i = 1 n g ( i ) S ( ⌊ n i ⌋ ) \sum_{i=1}^{n}\sum_{d|i}(f*g)(i)=\sum_{i=1}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor) i=1ndi(fg)(i)=i=1ng(i)S(in)变形可得:

g ( 1 ) S ( n ) + ∑ i = 2 n g ( i ) S ( ⌊ n i ⌋ ) = ∑ i = 1 n ( f ∗ g ) ( i ) g(1)S(n)+\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)=\sum_{i=1}^{n}(f*g)(i) g(1)S(n)+i=2ng(i)S(in)=i=1n(fg)(i)

g ( 1 ) S ( n ) = ∑ i = 1 n ( f ∗ g ) ( i ) − ∑ i = 2 n g ( i ) S ( ⌊ n i ⌋ ) g(1)S(n)=\sum_{i=1}^{n}(f*g)(i)-\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor) g(1)S(n)=i=1n(fg)(i)i=2ng(i)S(in) ( 1 ) (1) (1)

根据式(1),我们可以构造如下求 S ( n ) S(n) S(n)的方法:

考虑之前学过的常见积性函数间卷积运算转换的公式,我们构造合适的数论函数 g g g进行构造,函数 g g g显然需满足 f ∗ g f*g fg为一个可以快捷求出前缀和(这样一来,如果我们可以快速求出 ∑ i = 1 n ( f ∗ g ) ( i ) \sum_{i=1}^{n}(f*g)(i) i=1n(fg)(i))的函数且对于 ∀ x g ( x ) \forall xg(x) xg(x)易求。一般情况下,我们构造 g ( n ) = 1 g(n)=1 g(n)=1

这样一来,剩下的问题在于 ∑ i = 2 n g ( i ) S ( ⌊ n i ⌋ ) \sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor) i=2ng(i)S(in)怎么求:显然,我们可利用数论分块求此式的值。至于求和涉及到的每一项里 S ( ⌊ n i ⌋ ) S(\lfloor\frac{n}{i}\rfloor) S(in),我们可以再利用递推式 ( 1 ) (1) (1)求出它的值。

假设实际应用中涉及到的数论函数的值的线性表均线性复杂度可求,一般根据此方法直接递归计算的时间复杂度为 O ( n 3 4 ) O(n^{\frac{3}{4}}) O(n43)。考虑先线性筛预处理得到 S S S的前 n 2 3 n^{\frac{2}{3}} n32项,剩余部分时间复杂度为 O ( ∫ o n 1 3 n x d x ) = O ( n 2 3 ) O(\int_{o}^{n^{\frac{1}{3}}}\sqrt\frac{n}{x}dx)=O(n^{\frac{2}{3}}) O(on31xn dx)=O(n32),故整体算法时间复杂度为 O ( n 2 3 ) O(n^{\frac{2}{3}}) O(n32)

对于较大的 S S S的值,由于不同值的 S ( ⌊ n i ⌋ ) S(\lfloor\frac{n}{i}\rfloor) S(in)个数不会超过 2 n 2\sqrt n 2n 个,故用map存下其对应的值较为简便。

∑ i = 1 n μ ( i ) \sum_{i=1}^{n}\mu(i) i=1nμ(i)

考虑公式 μ ∗ 1 = ϵ \mu*1=\epsilon μ1=ϵ

f = μ , g = 1 f=\mu,g=1 f=μ,g=1,则:

g ( 1 ) S ( n ) = ∑ i = 1 n ( f ∗ g ) ( i ) − ∑ i = 2 n g ( i ) S ( ⌊ n i ⌋ ) g(1)S(n)=\sum_{i=1}^{n}(f*g)(i)-\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor) g(1)S(n)=i=1n(fg)(i)i=2ng(i)S(in)

↔ S ( n ) = ∑ i = 1 n ϵ ( i ) − ∑ i = 2 n S ( ⌊ n i ⌋ ) = 1 − ∑ i = 2 n S ( ⌊ n i ⌋ ) \leftrightarrow S(n)=\sum_{i=1}^{n}\epsilon(i)-\sum_{i=2}^{n}S(\lfloor\frac{n}{i}\rfloor)=1-\sum_{i=2}^{n}S(\lfloor\frac{n}{i}\rfloor) S(n)=i=1nϵ(i)i=2nS(in)=1i=2nS(in)

算法时间复杂度为 O ( n 2 3 ) O(n^{\frac{2}{3}}) O(n32)

∑ i = 1 n φ ( i ) \sum_{i=1}^{n}\varphi(i) i=1nφ(i)

考虑公式 φ ∗ 1 = i d \varphi*1=id φ1=id

f = φ , g = 1 f=\varphi,g=1 f=φ,g=1,则:

g ( 1 ) S ( n ) = ∑ i = 1 n ( f ∗ g ) ( i ) − ∑ i = 2 n g ( i ) S ( ⌊ n i ⌋ ) g(1)S(n)=\sum_{i=1}^{n}(f*g)(i)-\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor) g(1)S(n)=i=1n(fg)(i)i=2ng(i)S(in)

↔ S ( n ) = ∑ i = 1 n i d ( i ) − ∑ i = 2 n S ( ⌊ n i ⌋ ) = ∑ i = 1 n i − ∑ i = 2 n S ( ⌊ n i ⌋ ) = n ( n + 1 ) 2 − ∑ i = 2 n S ( ⌊ n i ⌋ ) \leftrightarrow S(n)=\sum_{i=1}^{n}id(i)-\sum_{i=2}^{n}S(\lfloor\frac{n}{i}\rfloor)=\sum_{i=1}^{n}i-\sum_{i=2}^{n}S(\lfloor\frac{n}{i}\rfloor)=\frac{n(n+1)}{2}-\sum_{i=2}^{n}S(\lfloor\frac{n}{i}\rfloor) S(n)=i=1nid(i)i=2nS(in)=i=1nii=2nS(in)=2n(n+1)i=2nS(in)

算法时间复杂度为 O ( n 2 3 ) O(n^{\frac{2}{3}}) O(n32)

根据以上两个过程,不难看出选择合适的 g g g f ∗ g f*g fg的重要性。

Code

#include<cstdio>
#include<iostream>
#include<map>
#define ri register int
#define ll long long
using namespace std;

const int MAXN=1e6;
int T,cnt,prime[MAXN];
ll N,smu[MAXN+20],sphi[MAXN+20];
bool notprime[MAXN+20];
map<ll,ll>Smu;
map<ll,ll>Sphi;

void EulaSieve()
{
	smu[1]=1,sphi[1]=1,notprime[1]=true;
	for(ri i=2;i<=MAXN;++i)
	{
		if(!notprime[i]) prime[++cnt]=i,smu[i]=-1,sphi[i]=i-1;
		for(ri j=1;j<=cnt&&i*prime[j]<=MAXN;++j)
		{
			notprime[i*prime[j]]=true;
			if(i%prime[j]==0)	sphi[i*prime[j]]=sphi[i]*prime[j];
			else	sphi[i*prime[j]]=sphi[i]*sphi[prime[j]];
			if(i%prime[j]==0) break;
			else smu[i*prime[j]]=-smu[i];
		}
	}
	for(ri i=1;i<=MAXN;++i) 
		smu[i]=smu[i-1]+smu[i],sphi[i]=sphi[i-1]+sphi[i];
}

ll S_mu(ll n)
{
	if(n<=MAXN) return smu[n];
	if(Smu[n]) return Smu[n];
	ll ans=1LL;
	for(ll l=2,r;l<=n;l=r+1)
	{
		r=n/(n/l);
		ans-=(r-l+1)*S_mu(n/l);
	}	
	return Smu[n]=ans;
}

ll S_phi(ll n)
{
	if(n<=MAXN) return sphi[n];
	if(Sphi[n]) return Sphi[n];
	ll ans=n*(n+1)/2LL;
	for(ll l=2,r;l<=n;l=r+1)
	{
		r=n/(n/l);
		ans-=(r-l+1)*S_phi(n/l);	
	}
	return Sphi[n]=ans;
}

int main()
{
	std::ios::sync_with_stdio(false);
	cin>>T;
	EulaSieve();
	for(ri op=1;op<=T;++op)
	{
		cin>>N;
		cout<<S_phi(N)<<" "<<S_mu(N)<<'\n';
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值