其他分享
首页 > 其他分享> > 【题解】BZOJ P1801 dp

【题解】BZOJ P1801 dp

作者:互联网

一个需要考虑比较多状态的dp


 

通过象棋规则可知,一列最多有两个炮

因为如果有三个炮他们就可以互相伤害了

 

设f[i][j][k]为前i行,有j列有一个棋子,有k列有两个棋子

容斥一下可得没有棋子的列数为m-j-k

我们枚举方棋子的状态

<1>只放一个棋子

(1) 把这个棋子放在一列没有棋子的列上

 当这个棋子放好之后,有一个棋子的列会+1,没有棋子的列会-1

  f[i][j][k]=f[i][j][k]+f[i-1][j-1][k]*(m-j-k+1)

(2)把这个棋子放在一列有一个棋子的列上

 当这个棋子放好之后,有一个棋子的列会-1,有两个棋子的列会+1

  f[i][j][k]=f[i][j][k]+f[i-1][j+1][k-1]*(j+1)

<2>放两个棋子

(1) 一个放在没棋子的列上,一个放在有一个棋子的列上

 当这两个棋子放好之后,有一个棋子的列会+1,有两个棋子的列会+1,没有棋子的列会-1

   f[i][j][k]=f[i][j][k]+f[i-1][j][k-1]*j*(m-j-k+1)

(2) 两个都放在有一个棋子的列上

 当这个棋子放好之后,有一个棋子的列会-2,有两个棋子的列会+2

  f[i][j][k]=f[i][j][k]+f[i-1][j+2][k-2]*(j+2)*(j+1)/2

(3) 两个都放在没有棋子的列上

 当这个棋子放好之后,有一个棋子的列会+2,没有棋子的列会-2

  f[i][j][k]=f[i][j][k]+f[i-1][j-2][k]*(m-j-k+2)*(m-j-k+1)/2


code

//
//  main.cpp
//  bzoj
//
//  Created by gengyf on 2019/7/18.
//  Copyright © 2019 yifan Geng. All rights reserved.
//

#include <bits/stdc++.h>
using namespace std;
namespace gengyf{
    inline int read(){
        int f=1,x=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return f*x;
    }
#define mod 9999973
    int n,m,ans;
    int f[105][105][105];
    inline int C(int x){
        return x*(x-1)/2%mod;
    }
    int main(){
        n=read();m=read();
        f[0][0][0]=1;
        for(int i=1;i<=n;i++)
            for(int j=0;j<=m;j++)
                for(int k=0;k<=m-j;k++){
                    f[i][j][k]=f[i-1][j][k];
                    if(k>=1)f[i][j][k]+=f[i-1][j+1][k-1]*(j+1);//放有一个
                    if(j>=1)f[i][j][k]+=f[i-1][j-1][k]*(m-j-k+1);//放没棋子
                    if(k>=1)f[i][j][k]+=f[i-1][j][k-1]*j*(m-j-k+1);
                    //放两个,一个在没棋子的,一个在有一个棋子的
                    if(k>=2)f[i][j][k]+=f[i-1][j+2][k-2]*C(j+2);
                    //放两个,都放在有一个棋子的
                    if(j>=2)(f[i][j][k]+=f[i-1][j-2][k]*C(m-j-k+2));
                    //放两个,都放在没棋子的
                    f[i][j][k]%=mod;
                }
        for(int i=0;i<=m;i++)
            for(int j=0;j<=m;j++){
                ans+=f[n][i][j];
                ans%=mod;
            }
        printf("%d",(ans+mod)%mod);
        return 0;
    }
}
int main() {
    gengyf::main();
    return 0;
}

 

标签:两个,一个,题解,列上,放在,棋子,P1801,列会,dp
来源: https://www.cnblogs.com/gengyf/p/11210762.html