bzoj2302: [HAOI2011]Problem c

    xiaoxiao2021-03-25  182

    bzoj2302: [HAOI2011]Problem c


    OI题有三种从一般到特殊,从暴力到优化,换角度思考 WerkeyTom_FTD 这道题让我认识到了从题目到充要条件的转换这种解题思路 这道题我们可以看出他的充要条件为 j,ni=1[ai>=j]<=nj+1 现在我们要求的便为满足这个条件的序列的合法方案数,这个东西就很好dp了 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; }
    转载请注明原文地址: https://ju.6miu.com/read-989.html

    最新回复(0)