bzoj2302: [HAOI2011]Problem c
题目链接
题解
s[i]表示m个人中编号> i的人数
设dp[i][j] 表示在剩余人中编号大于i的有j的方案数
\(dp[i][j] = \sum_{k = 0}^j dp[i + 1][k] * C_j^{j - k};\)
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read() {
int x = 0,f = 1;
char c = getchar();
while(c < '0' || c > '9')c = getchar();
while(c <= '9' && c >= '0')x = x * 10 + c- '0',c = getchar();
return x * f;
}
const int maxn = 307;
int p[maxn],q[maxn],sum[maxn];
int n,m,mod ;
int dp[maxn][maxn];
int C[maxn][maxn];
main() {
int t = read();
while(t --) {
memset(sum,0,sizeof sum);
n = read();m = read(); mod = read() ;
for(int i = 1;i <= m;++ i) p[i] = read(),sum[q[i] = read()] ++;
bool flag = 0;
for(int i = n;i ;-- i) {
sum[i] += sum[i + 1];
if(sum[i] > n - i + 1) {
flag = 1; break;
}
}
if(flag) {puts("NO"); continue;}
for(int i = 0;i <= 300;++ i) C[i][0] = 1;
for(int i = 1;i <= 300;++ i) for(int j = 1;j <= i;++ j)
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
//printf("%lld\n",C[300][5]);
memset(dp,0,sizeof dp);
dp[n + 1][0] = 1;
for(int i = n;i;-- i) {
for(int j = 0;j <= n - i - sum[i] + 1; ++ j)
for(int k = 0;k <= j; ++ k) {
//int *x = &dp[i][j];
int y = dp[i + 1][j - k];
dp[i][j] = (dp[i][j] + y * C[j][k]) % mod;
}
}
printf("YES %lld\n",dp[1][n - m]);
}
} .