Expected Median CodeForces - 1999F
- 题意
- 思路
- 代码
题意
思路
● 观察得:子序列的贡献只有0/1
两种,且题目属于
n
n
n元集合选
k
k
k元子集的统计类问题,且子集为中位数,故与排列顺序无关
● 正难则反,优先反向考虑
● 统计0
和1
的数量,考虑中位数贡献得:
○ 若不存在0
的影响,则答案为
C
n
k
C_n^k
Cnk
○ 考虑0的影响,则0
存在负贡献时,0
在
k
k
k元子集中的个数必须大于等于
(
k
+
1
)
/
2
(k+1)/2
(k+1)/2
○ 故从
(
k
+
1
)
/
2
−
m
i
n
(
k
,
c
o
u
n
t
s
o
f
0
)
(k+1)/2-min(k,counts\space of\space 0)
(k+1)/2−min(k,counts of 0)依次减去它的负贡献即可
● 负贡献,即在0
中选的元素个数和在1
中选的剩余个数的两种组合数相乘
代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10,mod=1e9+7;
#define int long long
int n,k;
inline int qmi(int a,int b,int p){
int ans=1%p;
for(;b;b>>=1){
if(b&1) ans=(long long)ans*a%p;
a=(long long)a*a%p;
}
return ans;
}
int P1[N],P2[N];
inline int C(int a,int b){
if(a<b) return 0ll%mod;
return 1ll*P1[a]*P2[b]%mod*P2[a-b]%mod;
}
inline void init(int tot){
P1[0]=1;
for(int i=1;i<=tot;i++) P1[i]=1ll*P1[i-1]*i%mod;
P2[tot]=qmi(P1[tot],mod-2,mod);
for(int i=tot-1;i>=0;i--) P2[i]=1ll*P2[i+1]*(i+1)%mod;
}
inline void add(int &a,int b){
a+=b;
if(a>=mod) a-=mod;
}
inline void del(int &a,int b){
a-=b;
if(a<0) a+=mod;
}
void solve(){
cin>>n>>k;
int pz=0,p1=0;
for(int i=1;i<=n;i++){
int x;
cin>>x;
if(x) p1++;
else pz++;
}
int res=C(n,k);
int down=0;
for(int i=(k+1)/2;i<=min(pz,k);i++)
add(down,C(pz,i)*C(p1,k-i)%mod);
del(res,down);
cout<<res<<'\n';
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
init(N-1);
int t;
t=1;
cin>>t;
while(t--){
solve();
}
}```