题解 CF1999F Expected Median

【洛谷专栏】

如果把 \(01\) 序列改为正整数序列,此题该如何应对。

题意

给定一个长度为 \(n\)\(01\) 序列,求所有长度为 \(k\)子序列中位数之和(\(k\) 为奇数),答案对 \(10^9 + 7\) 取模。

分析

因为 \(01\) 序列只含两个数,且只有中位数为 \(1\) 的情况会对答案产生影响。

\(s\)\(1\) 的个数,当 \(1\) 的个数大于等于 \(\dfrac {k+1} 2\) 时中位数才为 \(1\),考虑枚举 \(1\) 的个数 \(i\)\(1\) 的选择方案数为 \(\dbinom s i\)\(0\) 的选择方案数为 \(\dbinom{n-s}{k-i}\),所以子序列方案数为 \(\dbinom s i \dbinom{n-s}{k-i}\)

答案即为:

\[\sum\limits_{i=\frac{k+1} 2}^{\min(s,k)} \dbinom s i \dbinom{n-s}{k-i} \]

至于求组合数的方法可以参考 B3717 组合数问题,提前预处理阶乘和逆元可以做到 \(O(1)\) 求组合数。

单次时间复杂度为 \(O(k)\)

代码

//the code is from chenjh
#include<cstdio>
#define MAXN 200002
using namespace std;
typedef long long LL;
const int mod=1000000007;
int f[MAXN],v[MAXN];
int C(const int n,const int m){return n<m?0:(LL)f[n]*v[m]%mod*v[n-m]%mod;}//组合数。
int n,k;
void solve(){
	scanf("%d%d",&n,&k);
	int s=0,ans=0;
	for(int i=1,x;i<=n;i++) scanf("%d",&x),s+=x;
	for(int i=(k+1)>>1,mi=s<k?s:k;i<=mi;i++) ans=(ans+(LL)C(s,i)*C(n-s,k-i)%mod)%mod;
	printf("%d\n",ans);
}
int main(){
	*f=f[1]=*v=v[1]=1;
	for(int i=2;i<MAXN;i++) f[i]=(LL)f[i-1]*i%mod,v[i]=(LL)(mod-mod/i)*v[mod%i]%mod;//预处理阶乘和逆元。
	for(int i=1;i<MAXN;i++) v[i]=(LL)v[i-1]*v[i]%mod;//预处理阶乘的逆元。
	int T;scanf("%d",&T);
	while(T--) solve();
	return 0;
}
posted @ 2025-02-09 20:03  Chen_Jinhui  阅读(15)  评论(0)    收藏  举报