题目大意:
给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 }