隐藏
「广州集训 Day3」CTSC选拔 - 组合数 | Bill Yang's Blog

路终会有尽头,但视野总能看到更远的地方。

0%

「广州集训 Day3」CTSC选拔 - 组合数

题目大意

$n$人参加信息学竞赛,共有$m$道题。现在比赛已经结束,评分正在进行中,对于已经结束评测的试题,已知每名考生这道题的答案是否正确,对于未结束评测的试题,只知道每名考生是否提交答案。每个题分数固定,提交正确的答案的考生可以得到这一题的分数,分数越高排名越靠前,分数相同编号小的考生排名靠前。这$n$人中,排名最靠前的$s$人将获得入选代表队的资格,而这$s$个中将通过最终的科学委员会面试选出其中的$t$ 个人。输入当前的评测信息(包括是否提交,以及已经评测部分的是否正确)以及每道题的分值,问最终的$t$人代表队共有多少种组队的可能。


题目分析

WC2012讲的一道原题啊~
这道题要是直接想比较复杂,不如换个思路。

计算出每个人可能的最高成绩和最低成绩,按照可能最高成绩排序。
我们设$i$是$t$人代表队中的最后一名。
为什么要按照可能的最高成绩排序?这样就可以保证在$i$前面的人都有可能进入$s$人代表队。
设在$i$前面的人有$tot$个的最低成绩都比$i$高(这$tot$个人必在$s$中)


如图,当$i$为$t$人代表队最后一名,共有$C_{tot}^xC_{i-1-tot}^{t-x-1}$种合法方案。

计算的时候注意一下组合数边界。


题目总结

这是统计方案题的另一种思路。
选定一个基准元素,以基准元素为边界进行统计,但要保证这样做不会重复或遗漏,否则就又要玄学容斥了。


代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
typedef long long LL;
inline const LL Get_Int() {
LL num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}
const int maxn=55;
int n,m;
LL a[maxn],C[maxn][maxn],s,t,ans=0;
struct Point {
LL min,max;
int pos;
bool operator < (const Point& b) const {
return (max>b.max)||(max==b.max&&pos<b.pos);
}
} p[maxn];
int main() {
m=Get_Int();
for(int i=1; i<=m; i++)a[i]=Get_Int();
n=Get_Int();
for(int i=1; i<=n; i++) {
p[i].pos=i;
for(int j=1; j<=m; j++) {
char x=' ';
while(x!='Y'&&x!='N')x=getchar();
if(x=='Y') {
p[i].max+=abs(a[j]);
p[i].min+=max(a[j],0ll);
}
}
}
C[0][0]=1;
for(int i=1; i<=n; i++) {
C[i][0]=C[i][i]=1;
for(int j=1; j<i; j++)C[i][j]=C[i-1][j]+C[i-1][j-1];
}
s=Get_Int();
t=Get_Int();
sort(p+1,p+n+1);
for(int i=1; i<=n; i++) {
LL tot=0;
for(int j=1; j<i; j++)
if(p[j].min>p[i].max||p[j].min==p[i].max&&p[j].pos<p[i].pos)tot++;
for(LL x=max(0ll,max(t+tot-i,tot-s+t)); x<=min(tot,t-1); x++)ans+=C[tot][x]*C[i-tot-1][t-x-1];
}
printf("%lld\n",ans);
return 0;
}
姥爷们赏瓶冰阔落吧~