1. 程式人生 > >BZOJ1801[Ahoi2009]chess 中國象棋

BZOJ1801[Ahoi2009]chess 中國象棋

its using print content tps 另一個 一次 color www.

Time Limit: 10 Sec Memory Limit: 64 MB
Submit: 2433 Solved: 1460
[Submit][Status][Discuss]

Description

在N行M列的棋盤上,放若幹個炮可以是0個,使得沒有任何一個炮可以攻擊另一個炮。 請問有多少種放置方法,中國像棋中炮的行走方式大家應該很清楚吧.

Input

一行包含兩個整數N,M,中間用空格分開.

Output

輸出所有的方案數,由於值比較大,輸出其mod 9999973

Sample Input

1 3

Sample Output

7

HINT

除了在3個格子中都放滿炮的的情況外,其它的都可以.


100%的數據中N,M不超過100
50%的數據中,N,M至少有一個數不超過8
30%的數據中,N,M均不超過6

顯然問題就是一行一列最多只能放兩個棋子,求方案數 dp:f[i][j][k]表示前i行已經有j列有一個棋子,k列有兩個棋子的方案數 那麽第i行可以不放棋子、放一個棋子、放兩個棋子。 其中,棋子可以放在原來沒有棋子的某一列上,也可以放在已經有一個棋子的某一列上。但是已經有兩個棋子的列上是不能放的。 然後要分6種情況討論下。這裏想法其實不難,但是容易亂……我還wa了一次 1、不放 2、一個棋子,放在原來沒棋子的某一列上 3、一個棋子,放在原來有一個棋子的某一列上 4、兩個棋子,一個在原來沒棋子的列上,一個在原來一個棋子的列上 5、兩個棋子,都放在原來沒棋子的列上 6、兩個棋子,都放在原來一個棋子的列上
#include <bits/stdc++.h>
using
namespace std; const int mod = 9999973; typedef long long ll; int n,m; ll f[105][105][105]; int C(int m){ return m*(m-1)/2; } int main(){ scanf("%d%d",&n,&m); 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){ //don‘t push f[i][j][k] = f[i-1][j][k]; //push 1 in the cow had 0 if (j > 0) f[i][j][k] = (f[i][j][k] + f[i-1][j-1][k]*(m-j-k+1)) % mod; //push 1 in the cow had 1 if (k > 0 && j+1 <= m) f[i][j][k] = (f[i][j][k] + f[i-1][j+1][k-1] * (j+1)) % mod; //push 2 in the cow had 0 if (j >= 2) f[i][j][k] = (f[i][j][k] + f[i-1][j-2][k] * C(m-j-k+2)) % mod; //push 1 in the cow had 0 && push 1 in the cow had 1 if (j && k) f[i][j][k] = (f[i][j][k] + f[i-1][j][k-1] * (m-j-k+1) * (j)) % mod; //push 2 in the cow had 1 if (k >= 2 && j+2 <= m) f[i][j][k] = (f[i][j][k] + f[i-1][j+2][k-2] * C(j+2)) % mod; } } } ll ans = 0; for (int j = 0;j <= m;++j){ for (int k = 0;k <= m-j;++k){ ans = (ans + f[n][j][k]) % mod; } } printf("%lld\n",ans); return 0; }

BZOJ1801[Ahoi2009]chess 中國象棋