[luoguP2051] [AHOI2009]中國象棋(DP)
阿新 • • 發佈:2017-09-29
show include ble 當前 一個 () print long www.
傳送門
註釋寫明了一切
#include <cstdio> #define N 111 #define p 9999973 #define LL long long int n, m; LL ans, f[N][N][N]; //每一行和每一列可以放0/1/2個炮 //f[i][j][k]表示前i行放了1個炮的列有j個,放了2個炮的列有k個的方案數 //那麽可以推出,放了0個炮的列有m-j-k個 inline int C(int x) { return x * (x - 1) / 2; } int main() { int i, j, k, l; scanf("%d %d", &n, &m); f[0][0][0] = 1; for(i = 1; i <= n; i++) for(j = 0; j <= m; j++) for(k = 0; k <= m - j; k++) { //當前這一行不放炮 f[i][j][k] += f[i - 1][j][k]; //當前這一行就放一個炮 //放到沒有炮的列 if(j) f[i][j][k] += (m - k - j + 1) * f[i - 1][j - 1][k]; //放到有炮的列 if(k) f[i][j][k] += (j + 1) * f[i - 1][j + 1][k - 1]; //當前這一行放兩個炮 //放到兩個沒有炮的列 if(j >= 2) f[i][j][k] += C(m - k - j + 2) * f[i - 1][j - 2][k]; //放到兩個有炮的列 if(k >= 2) f[i][j][k] += C(j + 2) * f[i - 1][j + 2][k - 2]; //放到一個有炮的列,一個沒有炮的列 if(j && k) f[i][j][k] += j * (m - j - k + 1) * f[i - 1][j][k - 1]; f[i][j][k] %= p; } for(i = 0; i <= m; i++) for(j = 0; j <= m - i; j++) ans = (ans + f[n][i][j]) % p; printf("%lld\n", ans); return 0; }
[luoguP2051] [AHOI2009]中國象棋(DP)