# bzoj2302: [HAOI2011]Problem c

OI题有三种从一般到特殊，从暴力到优化，换角度思考 WerkeyTom_FTD

j,ni=1[ai>=j]<=nj+1

f[i][j]表示>=i的a有j个的合法方案数,r[i]表示被钦定为a(a=i)的人有多少个
m[i]表示被钦定为a(a>i)的人有多少个
f[i][j]=jr[i]k=0f[i+1][k]Cjkr[i]nkm[i]+l[j<=ni+1]

#include<cstdio>
#include<algorithm>
#include<cstring>

const int N = 310;

int C[N][N], p[N], n, m, k, a1, a2, P, f[N][N], r[N];

void Solve () {
memset (f, 0, sizeof f);
scanf ("%d%d%d", &n, &m, &P);
memset (C, 0, sizeof C);
C[0][0] = 1;
for (int i = 1; i <= 300; ++i) {
C[i][0] = 1;
for (int j = 1; j <= i; ++j) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % P;
}
for (int i = 1; i <= n; ++i) p[i] = -1, r[i] = 0;
for (int i = 1; i <= m; ++i) scanf ("%d%d", &a1, &a2), ++r[a2];
for (int i = n, l = 0; i; --i) {
l += r[i];
if (n - i + 1 < l) {
puts ("NO");
return ;
}
}
f[n + 1][0] = 1;
for (int i = n, l = 0; i; --i) {
for (int j = l; j <= n - i + 1; ++j)
for (int k = 0; k <= j - r[i]; ++k)
f[i][j] = (f[i][j] + 1ll * f[i + 1][k] * C[n - k + l - m][j - k - r[i]] % P) % P;
l += r[i];
}
printf ("YES %d\n", f[1][n]);
}

int main () {
int T; scanf ("%d", &T);
while (T--) Solve ();
return 0;
}

posted @ 2017-03-08 12:24 DraZxlnDdt 阅读(...) 评论(...) 编辑 收藏