bzoj 2302 Problem c

题目大意:

n个人安排座位,设第i个人的编号为ai,大家依次入座,第i个人来了以后尝试坐到ai,坐到ai 之后的第一个空座位上 若从ai开始没有空座位 该安排方案就不合法

然而有m个人的编号已经确定,你只能安排剩下的人的编号,求有多少种合法的安排方案

思路:

开始把所有人编号设为0 

首先如果对于一个位置 编号在它之前的人之和小于这个位置 则无解

之后考虑 dp i j 表示j个人 最大编号为i的方案数

可以从i-1位置转移过来 枚举编号为i的人数 以及之前用了多少个人 

则 dp i j +=dp i-1 j-k * 组合数 这个组合数为可供自由选择的人数中选k-已经被安排在i未知的人数个人

预处理出组合数数组

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstdlib>
 6 #include<cstring>
 7 #include<queue>
 8 #include<map>
 9 #include<vector>
10 #define ll long long
11 #define inf 2139062143
12 #define MAXN 310
13 using namespace std;
14 inline int read()
15 {
16     int x=0,f=1;char ch=getchar();
17     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
18     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
19     return x*f;
20 }
21 int n,m,MOD,sum[MAXN],c[MAXN][MAXN];
22 ll dp[MAXN][MAXN];
23 int main()
24 {
25     int T=read();
26     while(T--)
27     {
28         memset(sum,0,sizeof(sum));memset(dp,0,sizeof(dp));memset(c,0,sizeof(c));
29         n=read(),m=read(),MOD=read(),c[0][0]=dp[0][0]=1,sum[0]=n-m;int x;
30         for(int i=1;i<=n;i++)
31             for(int j=c[i][0]=1;j<=i;j++)
32                 (c[i][j]+=c[i-1][j-1]+c[i-1][j])%=MOD;
33         for(int i=1;i<=m;i++) x=read(),sum[read()]++;
34         for(int i=1;i<=n;i++) {sum[i]+=sum[i-1];if(sum[i]<i) goto ed;}
35         for(int i=1;i<=n;i++)
36             for(int j=i;j<=sum[i];j++)
37                 for(int k=sum[i]-sum[i-1];k<=j-i+1;k++)
38                     (dp[i][j]+=dp[i-1][j-k]*c[sum[i-1]-j+k][k-sum[i]+sum[i-1]])%=MOD;
39         printf("YES %lld\n",dp[n][n]);continue;
40         ed: puts("NO");
41     }
42 }
View Code

猜你喜欢

转载自www.cnblogs.com/yyc-jack-0920/p/9491433.html