51nod 1327 棋盤遊戲

傳送門:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1327
思路:這道傻逼的noip 題竟然做了我一小會23333 ,還是弱啊
事實上很簡單,我們注意到可以按列dp ,類似於插入的方式,既然沒法直接做,我們我們記錄有多少列被空出來,於是設f[i][j][k] 爲到第i 列,有j 列空出來,到第i 列有kright 未滿足條件,然後暴力轉移就可以了。
複雜度:OM2N

代碼:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<algorithm>
#define N 52
#define M 202
using namespace std;
struct node { int l,r;}; 
node a[N];
const int P = 1000000007;
int n,m,f[M][M][N],C[M][M],ans,fact[M];
//f[i][j][k]表示到第i列,剩下j個列沒放,目前到第i列還剩下k個right未滿足
//轉移? 
bool cmp(node x,node y){ return x.l < y.l;}
inline void up(int &a,int b){
    a += b;
    if (a >= P) a -= P;
}

void init(){
    scanf("%d%d",&n,&m);
    for (int i = 1;i <= n; ++i) {
      scanf("%d%d",&a[i].l,&a[i].r);
      a[i].r = m - a[i].r + 1; }
    sort(a + 1,a + n + 1,cmp);
    memset(C,0,sizeof(C));
    for (int i = 0;i < M; ++i)  C[i][0] = 1;
    for (int i = 1;i < M; ++i)
      for (int j = 1;j <= i; ++j)
        up(C[i][j],C[i - 1][j] + C[i - 1][j - 1]);
    fact[0] = 1;
    for (int i = 1;i < M; ++i) fact[i] = 1LL * fact[i - 1] * i % P;
    for (int i = 1;i < M; ++i)
      for (int j = 1;j <= i; ++j)
        C[i][j] = 1LL * C[i][j] * fact[j] % P;
}


void DO_IT(){
    int ll,rr,block;
    memset(f,0,sizeof(f));
    f[0][0][0] = 1;
    for (int i = 0;i < m; ++i){
      ll = rr = block = 0;
      for (int j = 1;j <= n; ++j) ll += (a[j].l == i + 1),rr += (a[j].r == i + 1),block += ((a[j].l < i + 1)&&(a[j].r > i + 1));
      for (int j = 0;j <= i + 1; ++j)
        for (int k = 0;k <= n - rr; ++k)
          {  
            // printf("%d %d %d :%d\n",i,j,k,f[i][j][k]);
             if (j + 1 >= ll&&ll >= 1) up(f[i + 1][j + 1 - ll][k + rr],1LL * ll * C[j][ll - 1] % P * f[i][j][k] % P); 
             if (j >= ll) {
               up(f[i + 1][j + 1 - ll][k + rr],1LL * C[j][ll] * f[i][j][k] % P);
               if (k + rr >= 1) up(f[i + 1][j - ll][k + rr - 1],1LL * f[i][j][k] * C[j][ll]  % P * (k + rr) % P);
               if (block) up(f[i + 1][j - ll][k + rr],1LL * f[i][j][k] * C[j][ll] % P * block % P);
               }
          }
      }
    ans = 0;
    for (int i = 0;i <= m; ++i) up(ans,f[m][i][0]);
}

int main(){
    init();
    DO_IT();
    cout<<ans;
    return 0;
}

總結:1.寫代碼的時候一定要專心!
2.注意要分清楚排列數和組合數。。。不要總是搞錯

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章