【XSY4074】intervcl C(推式子,根号分类)

本文探讨了在编程竞赛中如何利用数学和算法优化解决方案。文章详细介绍了等概率选择情况下,求解数列中任取多个元素最大值期望的计算方法,通过排序、组合数学和范德蒙德卷积进行高效求解。此外,还讨论了预处理优化技巧,如动态规划和分治策略,以降低时间复杂度。
摘要由CSDN通过智能技术生成

题面

intervcl C

题解

首先询问和原数列顺序无关,那么不妨把数列从大到小排序,仍记为 a i a_i ai

那么题目就是给出 [ l , r ] [l,r] [l,r],问 a l , a l + 1 , ⋯   , a r a_l,a_{l+1},\cdots,a_r al,al+1,,ar 中任取 k k k 个数,这 k k k 个数中最大值的期望。

由于这是等概率选择,每种情况出现的概率为 1 ( m k ) \dfrac{1}{\binom{m}{k}} (km)1(记 m = r − l + 1 m=r-l+1 m=rl+1),所以我们只需计算每种情况的最大值之和即可。

容易想到直接枚举最大值为 a i a_i ai,那么剩余的 k − 1 k-1 k1 个数就必须从 a i + 1 , a i + 2 , ⋯   , a r a_{i+1},a_{i+2},\cdots,a_r ai+1,ai+2,,ar 里面选,方案数为 ( r − i k − 1 ) \dbinom{r-i}{k-1} (k1ri),故最大值为 a i a_i ai 的贡献为 a i × ( r − i k − 1 ) a_i\times \dbinom{r-i}{k-1} ai×(k1ri)

所以总和即为 ∑ i = l r ( r − i k − 1 ) × a i \sum\limits_{i=l}^r \dbinom{r-i}{k-1}\times a_i i=lr(k1ri)×ai

总时间复杂度 O ( n q ) O(nq) O(nq),上述部分都是比较容易想到的。

注意到 ∑ k ≤ 1 0 5 \sum k\leq 10^5 k105,考虑把单次询问从 O ( n ) O(n) O(n) O ( k ) O(k) O(k) 转换。

受到 subtask4 的启发,我们设 f k [ r ] = ∑ i = 1 r ( r − i k − 1 ) × a i f_k[r]=\sum\limits_{i=1}^r\dbinom{r-i}{k-1}\times a_i fk[r]=i=1r(k1ri)×ai,那么每次询问 [ l , r ] [l,r] [l,r] 的答案即为:
f k [ r ] − ∑ i = 1 l − 1 ( r − i k − 1 ) × a i f_k[r]-\sum_{i=1}^{l-1}\dbinom{r-i}{k-1}\times a_i fk[r]i=1l1(k1ri)×ai
试图也用 f f f 来表示 ∑ i = 1 l − 1 ( r − i k − 1 ) × a i \sum\limits_{i=1}^{l-1}\dbinom{r-i}{k-1}\times a_i i=1l1(k1ri)×ai
∑ i = 1 l − 1 ( r − i k − 1 ) × a i = ∑ i = 1 l − 1 ∑ j = 0 k − 1 ( r − l + 1 j ) ( l − 1 − i k − 1 − j ) × a i \begin{aligned} &\sum_{i=1}^{l-1}\dbinom{r-i}{k-1}\times a_i\\ =&\sum_{i=1}^{l-1}\sum_{j=0}^{k-1}\dbinom{r-l+1}{j}\dbinom{l-1-i}{k-1-j}\times a_i \end{aligned} =i=1l1(k1ri)×aii=1l1j=0k1(jrl+1)(k1jl1i)×ai
(上面这步用到了范德蒙德卷积)

范德蒙德卷积:
∑ i = 0 k ( n i ) ( m k − i ) = ( n + m k ) \sum_{i=0}^{k}\dbinom{n}{i}\dbinom{m}{k-i}=\dbinom{n+m}{k} i=0k(in)(kim)=(kn+m)
证明:从组合意义上即可理解,相当于从各有 n n n 个和 m m m 个的两堆中共取出 k k k 个球。

继续推:
∑ i = 1 l − 1 ( r − i k − 1 ) × a i = ∑ i = 1 l − 1 ∑ j = 0 k − 1 ( r − l + 1 k − 1 − j ) ( l − 1 − i j ) × a i = ∑ i = 1 l − 1 ∑ j − 1 k ( r − l + 1 k − j ) ( l − 1 − i j − 1 ) × a i = ∑ j − 1 k ( r − l + 1 k − j ) ∑ i = 1 l − 1 ( l − 1 − i j − 1 ) × a i = ∑ j − 1 k ( r − l + 1 k − j ) f j [ l − 1 ] \begin{aligned} &\sum_{i=1}^{l-1}\dbinom{r-i}{k-1}\times a_i\\ =&\sum_{i=1}^{l-1}\sum_{j=0}^{k-1}\dbinom{r-l+1}{k-1-j}\dbinom{l-1-i}{j}\times a_i\\ =&\sum_{i=1}^{l-1}\sum_{j-1}^{k}\dbinom{r-l+1}{k-j}\dbinom{l-1-i}{j-1}\times a_i\\ =&\sum_{j-1}^{k}\dbinom{r-l+1}{k-j}\sum_{i=1}^{l-1}\dbinom{l-1-i}{j-1}\times a_i\\ =&\sum_{j-1}^{k}\dbinom{r-l+1}{k-j}f_{j}[l-1]\\ \end{aligned} ====i=1l1(k1ri)×aii=1l1j=0k1(k1jrl+1)(jl1i)×aii=1l1j1k(kjrl+1)(j1l1i)×aij1k(kjrl+1)i=1l1(j1l1i)×aij1k(kjrl+1)fj[l1]
故每次询问 [ l , r ] [l,r] [l,r] 的答案就是:
f k [ r ] − ∑ j − 1 k ( r − l + 1 k − j ) f j [ l − 1 ] f_k[r]-\sum_{j-1}^{k}\dbinom{r-l+1}{k-j}f_{j}[l-1] fk[r]j1k(kjrl+1)fj[l1]
P = ∑ k P=\sum k P=k,那么这样询问的总时间复杂度就是 O ( q + P ) O(q+P) O(q+P) 的了,但是如果暴力 O ( k n 2 ) O(kn^2) O(kn2) 预处理 f f f 的话我们是无法接受的。

考虑优化预处理的过程:

观察定义式 f k [ r ] = ∑ i = 1 r ( r − i k − 1 ) × a i f_k[r]=\sum\limits_{i=1}^r\dbinom{r-i}{k-1}\times a_i fk[r]=i=1r(k1ri)×ai,由组合数递推公式 ( n m ) = ( n − 1 m ) + ( n − 1 m − 1 ) \dbinom{n}{m}=\dbinom{n-1}{m}+\dbinom{n-1}{m-1} (mn)=(mn1)+(m1n1) 可知:
f k [ r ] = ∑ i = 1 r ( r − i k − 1 ) × a i = ∑ i = 1 r [ ( r − i − 1 k − 1 ) + ( r − i − 1 k − 2 ) ] × a i = f k [ r − 1 ] + f k − 1 [ r − 1 ] \begin{aligned} f_k[r]&=\sum\limits_{i=1}^r\dbinom{r-i}{k-1}\times a_i\\ &=\sum\limits_{i=1}^r\left[\dbinom{r-i-1}{k-1}+\dbinom{r-i-1}{k-2}\right]\times a_i\\ &=f_{k}[r-1]+f_{k-1}[r-1] \end{aligned} fk[r]=i=1r(k1ri)×ai=i=1r[(k1ri1)+(k2ri1)]×ai=fk[r1]+fk1[r1]
于是预处理 f f f 的时间复杂度由 O ( k n 2 ) O(kn^2) O(kn2) 降到了 O ( k n ) O(kn) O(kn),但这样还是不够。

我们考虑设置一个阈值 B B B

  • k > B k> B k>B 时我们使用最开始说的暴力算法,这种算法的使用次数不会超过 P B \dfrac{P}{B} BP,总时间复杂度 O ( n P B ) O(\dfrac{nP}{B}) O(BnP)

  • k ≤ B k\leq B kB 时我们先 O ( n B ) O(nB) O(nB) 预处理出所有的 f k [ r ] f_k[r] fk[r],然后再 O ( q + P ) O(q+P) O(q+P) 询问。

总时间复杂度 O ( n B + n P B ) O(nB+\dfrac{nP}{B}) O(nB+BnP),注意到 n , P n,P n,P 同阶,取 B = P B=\sqrt P B=P 时有最优的时间复杂度 O ( n n ) O(n\sqrt n) O(nn )

#include<bits/stdc++.h>

#define SN 320
#define N 100010

using namespace std;

namespace modular
{
	const int mod=998244353;
	inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
	inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
	inline int mul(int x,int y){return 1ll*x*y%mod;}
}using namespace modular;

inline int poww(int a,int b)
{
	int ans=1;
	while(b)
	{
		if(b&1) ans=mul(ans,a);
		a=mul(a,a);
		b>>=1;
	}
	return ans;
}

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}

int n,q,B,a[N],b[N];
int fac[N],ifac[N];
int f[SN][N];

int C(int n,int m)
{
	if(n<0||m<0||m>n) return 0;
	return mul(mul(fac[n],ifac[m]),ifac[n-m]);
}

int solve1(int l,int r,int k)
{
	int ans=0;
	for(int i=l;i<=r;i++)
		ans=add(ans,mul(C(r-i,k-1),a[i]));
	return ans;
}

int solve2(int l,int r,int k)
{
	int ans=f[k][r];
	for(int j=1;j<=k;j++)
		ans=dec(ans,mul(C(r-l+1,k-j),f[j][l-1]));
	return ans;
}

int main()
{
	n=read(),q=read(),B=sqrt(n);
	for(int i=1;i<=n;i++) a[i]=read();
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++) b[i]=a[i];
	reverse(a+1,a+n+1);
	fac[0]=1;
	for(int i=1;i<=100000;i++) fac[i]=mul(fac[i-1],i);
	ifac[100000]=poww(fac[100000],mod-2);
	for(int i=100000;i>=1;i--) ifac[i-1]=mul(ifac[i],i);
	for(int r=1;r<=n;r++) f[1][r]=add(f[1][r-1],a[r]);
	for(int k=2;k<=B;k++)
		for(int r=1;r<=n;r++)
			f[k][r]=add(f[k-1][r-1],f[k][r-1]);
	while(q--)
	{
		int l=read(),r=read(),k=read();
		l=lower_bound(b+1,b+n+1,l)-b;
		r=upper_bound(b+1,b+n+1,r)-b-1;
		swap(l,r);
		l=n-l+1,r=n-r+1;
		printf("%d ",r-l+1);
		if(k>r-l+1)
		{
			puts("-1");
			continue;
		}
		printf("%d\n",mul(k>B?solve1(l,r,k):solve2(l,r,k),poww(C(r-l+1,k),mod-2)));
	}
	return 0;
}
/*
7 3
83 74 100 89 95 79 72
90 100 3
80 89 1
70 79 2
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值