P6222 简单题加强版——各种推式子trick大杂烩

Description

∑ i = 1 n ∑ j = 1 n ( i + j ) t μ 2 ( gcd ⁡ ( i , j ) ) gcd ⁡ ( i , j ) \sum_{i=1}^n \sum_{j=1}^n (i+j)^t \mu^2(\gcd(i,j)) \gcd(i,j) i=1nj=1n(i+j)tμ2(gcd(i,j))gcd(i,j)

q q q组询问, t t t为常量, n n n为变量。每个答案都要对 2 32 2^{32} 232取模。 n ≤ 1 0 7 , q ≤ 1 0 4 n≤10^7,q≤10^4 n107,q104

时间限制 0.5 s − 1.5 s 0.5s-1.5s 0.5s1.5s,空间限制256MB

Solution

Part 1: 莫反推式子

一道比较套路的推式子题,中间用到了许多推式子的trick。

∑ i = 1 n ∑ j = 1 n ( i + j ) t μ 2 ( gcd ⁡ ( i , j ) ) gcd ⁡ ( i , j ) \sum_{i=1}^n \sum_{j=1}^n (i+j)^t \mu^2(\gcd(i,j)) \gcd(i,j) i=1nj=1n(i+j)tμ2(gcd(i,j))gcd(i,j)

= ∑ k = 1 n μ 2 ( k )   k   ∑ i = 1 n ∑ j = 1 n [ gcd ⁡ ( i , j ) = k ] ( i + j ) t =\sum_{k=1}^n \mu^2(k)\ k\ \sum_{i=1}^n \sum_{j=1}^n [\gcd(i,j)=k] (i+j)^t =k=1nμ2(k) k i=1nj=1n[gcd(i,j)=k](i+j)t

= ∑ k = 1 n μ 2 ( k )   k t + 1   ∑ i = 1 ⌊ n k ⌋ ∑ j = 1 ⌊ n k ⌋ [ gcd ⁡ ( i , j ) = 1 ] ( i + j ) t =\sum_{k=1}^n \mu^2(k)\ k^{t+1}\ \sum_{i=1}^{\lfloor \frac n k \rfloor} \sum_{j=1}^{\lfloor \frac n k \rfloor} [\gcd(i,j)=1] (i+j)^t =k=1nμ2(k) kt+1 i=1knj=1kn[gcd(i,j)=1](i+j)t

= ∑ k = 1 n μ 2 ( k )   k t + 1   ∑ i = 1 ⌊ n k ⌋ ∑ j = 1 ⌊ n k ⌋ ( ∑ d ∣ g c d ( i , j ) μ ( d ) )   ( i + j ) t =\sum_{k=1}^n \mu^2(k)\ k^{t+1}\ \sum_{i=1}^{\lfloor \frac n k \rfloor} \sum_{j=1}^{\lfloor \frac n k \rfloor} (\sum_{d|gcd(i,j)} \mu(d))\ (i+j)^t =k=1nμ2(k) kt+1 i=1knj=1kn(dgcd(i,j)μ(d)) (i+j)t

= ∑ k = 1 n μ 2 ( k )   k t + 1   ∑ d = 1 ⌊ n k ⌋ μ ( d )   d t   ( ∑ i = 1 ⌊ n k d ⌋ ∑ j = 1 ⌊ n k d ⌋ ( i + j ) t ) ) =\sum_{k=1}^n \mu^2(k)\ k^{t+1}\ \sum_{d=1}^{\lfloor \frac n k \rfloor} \mu(d)\ d^{t}\ (\sum_{i=1}^{\lfloor \frac n {kd} \rfloor} \sum_{j=1}^{\lfloor \frac n {kd} \rfloor} (i+j)^t)) =k=1nμ2(k) kt+1 d=1knμ(d) dt (i=1kdnj=1kdn(i+j)t))

F ( x ) = ∑ i = 1 x ∑ j = 1 x ( i + j ) f F(x)=\sum_{i=1}^x \sum_{j=1}^x (i+j)^f F(x)=i=1xj=1x(i+j)f,带入得

∑ k = 1 n μ 2 ( k )   k t + 1   ∑ d = 1 ⌊ n k ⌋ μ ( d )   d t   F ( ⌊ n k d ⌋ ) \sum_{k=1}^n \mu^2(k)\ k^{t+1}\ \sum_{d=1}^{\lfloor \frac n k \rfloor} \mu(d)\ d^{t}\ F(\lfloor \frac n {kd} \rfloor) k=1nμ2(k) kt+1 d=1knμ(d) dt F(kdn)

T = k d T=kd T=kd,转而枚举 T T T并将枚举 T T T ∑ \sum 提到最外层,

∑ T = 1 n F ( ⌊ n T ⌋ )   ∑ k ∣ T μ 2 ( k ) k t + 1 μ ( T k ) ( T k ) t \sum_{T=1}^n F(\lfloor \frac n T \rfloor)\ \sum_{k|T} \mu^2(k) k^{t+1} \mu(\frac T k) (\frac T k)^{t} T=1nF(Tn) kTμ2(k)kt+1μ(kT)(kT)t

= ∑ T = 1 n F ( ⌊ n T ⌋ )   T k   ∑ k ∣ T μ 2 ( k ) k   μ ( T k ) =\sum_{T=1}^n F(\lfloor \frac n T \rfloor)\ T^k\ \sum_{k|T} \mu^2(k) k\ \mu(\frac T k) =T=1nF(Tn) Tk kTμ2(k)k μ(kT)

G ( T ) = T k ∑ k ∣ T μ 2 ( k ) k   μ ( T k ) G(T)=T^k \sum_{k|T} \mu^2(k) k\ \mu(\frac T k) G(T)=TkkTμ2(k)k μ(kT),带入得

∑ T = 1 n F ( ⌊ n T ⌋ )   G ( T ) \sum_{T=1}^n F(\lfloor \frac n T \rfloor)\ G(T) T=1nF(Tn) G(T)

这不是卷积形式吗 可以发现这是一个整除分块的套路式。现在我们只需要快速求出单个 F F F以及一个区间的 G G G之和即可,而后者可以通过前缀和求出。所以现在我们只需要思考如何快速求出 F , G F,G F,G函数。

Part 2: 求函数F

先考虑 F ( n ) F(n) F(n)

∑ i = 1 n ∑ j = 1 n ( i + j ) f \sum_{i=1}^n \sum_{j=1}^n (i+j)^f i=1nj=1n(i+j)f

考虑去枚举 i + j i+j i+j。对于一个 ( i + j ) = s u m (i+j)=sum (i+j)=sum它的贡献是 s u m k   p s u m sum^k\ p_{sum} sumk psum,其中 p s u m p_{sum} psum表示任选两个在 [ 1 , n ] [1,n] [1,n]区间内的整数使得它们的和恰好为 s u m sum sum的方案数。

先考虑如何求出 p s u m p_{sum} psum。分类讨论:
①若 s u m ≤ n sum≤n sumn,那么 p s u m = s u m − 1 p_{sum}=sum-1 psum=sum1
②否则 p s u m = 2 n − s u m + 1 p_{sum}=2n-sum+1 psum=2nsum+1

我们枚举 s u m sum sum(即下式中的 i i i):

∑ i = 1 n ( i − 1 ) i k + ∑ i = n + 1 2 n ( 2 n − i + 1 )   i k \sum_{i=1}^n (i-1)i^k+\sum_{i=n+1}^{2n} (2n-i+1)\ i^k i=1n(i1)ik+i=n+12n(2ni+1) ik

= ( ∑ i = 1 n ∑ j = i + 1 n j k ) + ( ∑ i = n + 1 2 n ∑ j = n + 1 i j k ) =(\sum_{i=1}^n \sum_{j={i+1}}^n j^k)+(\sum_{i=n+1}^{2n} \sum_{j=n+1}^i j^k) =(i=1nj=i+1njk)+(i=n+12nj=n+1ijk)

S ( x ) = ∑ i = 1 x i f S(x)=\sum_{i=1}^x i^f S(x)=i=1xif,带入得

( ∑ i = 1 n S ( n ) − S ( i ) ) + ∑ i = n + 1 2 n   S ( i ) − S ( n ) (\sum_{i=1}^n S(n)-S(i))+\sum_{i=n+1}^{2n}\ S(i)-S(n) (i=1nS(n)S(i))+i=n+12n S(i)S(n)

= n S ( n ) − ∑ i = 1 n S ( i ) + ∑ i = n + 1 2 n   S ( i ) − n S ( n ) =nS(n)-\sum_{i=1}^n S(i)+\sum_{i=n+1}^{2n}\ S(i)-nS(n) =nS(n)i=1nS(i)+i=n+12n S(i)nS(n)

= ∑ i = n + 1 2 n S ( i ) − ∑ i = 1 n S ( i ) =\sum_{i=n+1}^{2n} S(i)-\sum_{i=1}^n S(i) =i=n+12nS(i)i=1nS(i)

= ( ∑ i = 1 2 n S ( i ) − ∑ i = 1 n S ( i ) ) − ∑ i = 1 n S ( i ) =(\sum_{i=1}^{2n} S(i)-\sum_{i=1}^n S(i))-\sum_{i=1}^n S(i) =(i=12nS(i)i=1nS(i))i=1nS(i)

S ′ ( x ) = ∑ i = 1 x S ( i ) S'(x)=\sum_{i=1}^x S(i) S(x)=i=1xS(i),带入得

F ( n ) = S ′ ( 2 n ) − 2 S ( n ) F(n)=S'(2n)-2S(n) F(n)=S(2n)2S(n)

于是我们对 S S S做两遍前缀和处理即可 O ( 1 ) O(1) O(1)调用求出 F F F

注意 S S S可以通过积性筛预处理求出来。

Part 3: 求函数G

观察一下: G ( T ) = ∑ k ∣ T μ 2 ( k ) k   μ ( T k ) G(T)=\sum_{k|T} \mu^2(k) k\ \mu(\frac T k) G(T)=kTμ2(k)k μ(kT)

可以发现,这个函数是由许多积性函数( i d , μ id,\mu id,μ)组成的。所以 G G G本身也是一个积性函数,所以可以考虑线性筛积性函数

线性筛积性函数只需要思考一种情况即可得到一般的筛法。这就是 T = p c T=p^c T=pc的情况,其中 p p p为质数且 c c c为自然数。

c = 0 c=0 c=0: 此时 T = 1 T=1 T=1 G ( T ) = 1 G(T)=1 G(T)=1
c = 1 c=1 c=1: 此时

G ( T ) = μ 2 ( 1 ) × 1 × μ ( T ) + μ 2 ( T ) × T × μ ( 1 ) G(T)=\mu^2(1)×1×\mu(T)+\mu^2(T)×T×\mu(1) G(T)=μ2(1)×1×μ(T)+μ2(T)×T×μ(1)

即在这种情况中 G ( T ) = T − 1 G(T)=T-1 G(T)=T1

c = 2 c=2 c=2: 显然只有 μ 2 ( p ) × p × μ ( p ) \mu^2(p)×p×\mu(p) μ2(p)×p×μ(p)能产生非 0 0 0的贡献,而这个值等于 1 × p × ( − 1 ) = − p 1×p×(-1)=-p 1×p×(1)=p,所以 G ( T ) = − p G(T)=-p G(T)=p

④当 c ≥ 3 c≥3 c3时,对于任意满足 u + v = c u+v=c u+v=c的正整数对 ( u , v ) (u,v) (u,v)都存在 u > 1 u>1 u>1 v > 1 v>1 v>1,而任何质数的超过 1 1 1次方的莫比乌斯函数值都是 0 0 0,所以此时 G ( T ) = 0 G(T)=0 G(T)=0


为什么说考虑了 T = p c T=p^c T=pc的情况之后就完全搞定了这种函数的积性筛呢?我们看一下 G G G的线性筛的代码:

//judge记录了这个数是否为合数
for (int i=2;i<=len;i++){
	if (!judge[i])  G[i]=i-1,prime[++pos]=i;
	//i是质数,对应的G值为i-1
	for (int j=1;j<=pos;j++){
		int p=prime[j];
		if (i*p>len)  break;//超过边界, 跳出
		judge[i*p]=1;//i*p为合数
		if (i%p==0){
			int q=i/p;
			if (q%p)  G[i*p]=-p*G[i/p];
			//核心语句,若不理解请先看下去
			break;
		}
		else G[i*p]=G[i]*G[p];//积性函数递推
	}
}

i i i p p p整除时,一定能分解成 i = p c × y i=p^c×y i=pc×y的形式,其中 c ≥ 1 c≥1 c1。即, i × p = p c ′ × y i×p=p^{c'}×y i×p=pc×y,其中 c ′ ≥ 2 c'≥2 c2

由于 p p p为质数,所以 p c ′ p^{c'} pc y y y互质,即 G ( i p ) = G ( p c ′ ) × G ( y ) G(ip)=G(p^{c'})×G(y) G(ip)=G(pc)×G(y) G ( p c ′ ) G(p^{c'}) G(pc)就是我们上面分类讨论的东西, G ( y ) G(y) G(y)是可以 O ( 1 ) O(1) O(1)调用的东西。所以这样就可以完成线性筛。

Part 4: 空间复杂度与时间复杂度的评估

本题严重卡空间,所以开的数组必须很少,只需要开下面几个数组:

p r i m e prime prime(素数)集合,由于在 [ 1 , 2 × 1 0 7 ] [1,2×10^7] [1,2×107]内的质数很少,所以这个集合可以少开一点或者直接使用 v e c t o r vector vector
②素数校验器 j u d g e judge judge,一定要开成bool;
G G G函数与 i k i^k ik函数。

不难发现, F F F函数可以直接调用 i k i^k ik函数 O ( 1 ) O(1) O(1)求出,不需要预处理,直接放在主函数中除了大了几倍时间常数之外并无大碍。

考虑这个空间是多少,并令 m = 2 × 1 0 7 m=2×10^7 m=2×107
p r i m e prime prime: 开到 m 2 \frac {m} 2 2m
②③开到 m m m

由于 b o o l bool bool占用的空间只有 i n t int int的一半,所以总空间占用为 m 2 + m 2 + m + m = 3 m = 6 × 1 0 7 \frac m 2+\frac m 2+m+m=3m=6×10^7 2m+2m+m+m=3m=6×107。同时,我们不开 l o n g   l o n g long\ long long long,采用unsigned int使其自然溢出实现取模即可防止 M L E MLE MLE

时间并没有卡得很厉害,只要复杂度正确并且开了 O 2 O2 O2提交就能过。

总时间复杂度 O ( n ln ⁡ ( n ) log ⁡ k + n + T n ) O(\frac n {\ln(n)} \log k+n+T \sqrt n) O(ln(n)nlogk+n+Tn )

Summary

这是一道套路题,考察了推式子的能力与一些卡空间的trick。

本题先使用了莫比乌斯反演得到了一个简化的式子,将问题拆成了两个子问题: 求出函数 F F F G G G。在求 F F F过程中我们巧妙枚举了 i + j i+j i+j,并将系数转化得到简明扼要的式子;在求 G G G过程中我们巧妙运用了积性函数的性质,使用分类讨论+线性筛求出了 G G G。最终,我们卡了一波空间,苦尽甘来,正解出现。

Code

//by ducati
#include<bits/stdc++.h>
#define int unsigned int
using namespace std;
const int maxl=20005;

int t,len,k,n,pos=0,ans=0;
int prime[maxl/5],pre_k[maxl],f[maxl];
bool judge[maxl];

int quick_power(int x,int y){
	int res=1;
	for (;y;y=y>>1,x*=x)
	  if (y&1)  res*=x;
	return res;
}

void init(){
	pre_k[1]=1,f[1]=1;
	for (int i=2;i<=len;i++){
		if (!judge[i])  pre_k[i]=quick_power(i,k),f[i]=i-1,prime[++pos]=i;
		for (int j=1;j<=pos;j++){
			int p=prime[j];
			if (i*p>len)  break;
			pre_k[i*p]=pre_k[i]*pre_k[p];
			judge[i*p]=1;
			if (i%p==0){
				int q=i/p;
				if (q%p)  f[i*p]=-p*f[i/p];
				break;
			}
			else f[i*p]=f[i]*f[p];
		}
	}
	for (int i=1;i<=len;i++)  f[i]=f[i-1]+f[i]*pre_k[i];
	for (int i=1;i<=len;i++)  pre_k[i]+=pre_k[i-1];
	for (int i=1;i<=len;i++)  pre_k[i]+=pre_k[i-1];
}
int calc(int x){return pre_k[2*x]-2*pre_k[x];}

signed main(){
	cin>>t>>len>>k;len*=2;
	init();
	while (t--){
		cin>>n;ans=0;
		for (int l=1,r;l<=n;l++){
			r=n/(n/l);
			ans+=calc(n/l)*(f[r]-f[l-1]);
			l=r;
		}
		cout<<ans<<endl;
	}
	return 0;
}

sto Fee_clе6418 orz

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值