bzoj2302: [HAOI2011]Problem c

题目链接

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]);     
    }     
}     .
posted @ 2018-07-23 19:25  zzzzx  阅读(207)  评论(0编辑  收藏  举报