BZOJ1801 [Ahoi2009]chess 中國象棋 【dp】
阿新 • • 發佈:2018-01-19
pri name include 題解 中國象棋 c++ down 不同 ostream
題目
在N行M列的棋盤上,放若幹個炮可以是0個,使得沒有任何一個炮可以攻擊另一個炮。 請問有多少種放置方法,中國像棋中炮的行走方式大家應該很清楚吧.
輸入格式
一行包含兩個整數N,M,中間用空格分開.
輸出格式
輸出所有的方案數,由於值比較大,輸出其mod 9999973
輸入樣例
1 3
輸出樣例
7
提示
除了在3個格子中都放滿炮的的情況外,其它的都可以.
100%的數據中N,M不超過100
50%的數據中,N,M至少有一個數不超過8
30%的數據中,N,M均不超過6
題解
一道dp題
設\(f[i][j][k]\)表示前i行有j列放了一個炮,k列放了兩個炮
每行最多放兩個,分類討論轉移,是放在了沒有炮的行還是有炮的,一個還是兩個,全都放還是分別不同。
見代碼
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<‘ ‘; puts("");
using namespace std;
const int maxn = 105,maxm = 100005,INF = 1000000000,P = 9999973;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57) {if (c == ‘-‘) flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1 ) + c - ‘0‘; c = getchar();}
return out * flag;
}
int f[maxn][maxn][maxn],n,m;
int C(int x) {return x * (x - 1) >> 1;}
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; j + k <= m; k++){
f[i][j][k] = f[i - 1][j][k];
int& F = f[i][j][k];
if (j) F += (LL)(m - j - k + 1) * f[i - 1][j - 1][k] % P,F %= P;
if (j > 1) F += (LL)C(m - j - k + 2) * f[i - 1][j - 2][k] % P,F %= P;
if (k) F += (LL)(j + 1) * f[i - 1][j + 1][k - 1] % P,F %= P;
if (k > 1) F += (LL)C(j + 2) * f[i - 1][j + 2][k - 2] % P,F %= P;
if (k) F += (LL)j * (m - j - k + 1) % P * f[i - 1][j][k - 1] % P,F %= P;
}
int ans = 0;
for (int j = 0; j <= m; j++)
for (int k = 0; j + k <= m; k++)
ans = (ans + f[n][j][k]) % P;
printf("%d",ans);
return 0;
}
BZOJ1801 [Ahoi2009]chess 中國象棋 【dp】