T1 : 中国象棋
题面
在 (N) 行 (M) 列的棋盘上,放若干个炮可以是 (0) 个,使得没有任何一个炮可以攻击另一个炮。请问有多少种放置方法,中国像棋中炮的攻击方式大家应该很清楚吧,需要隔一颗棋子攻击。
题解
- (dp[i][j][k]) 表示现在放到了第i行,还有j列可以放1个,k列可以放两个
- 考虑转移:
- 填表法
- 如果这一行的答案为0, 无法转移直接
continue
。if (!dp[i][j][k]) continue;
- 如果是下一行一个不放,那么就直接转移就可以了。
dp[i + 1][j][k] = (dp[i][j][k] + dp[i + 1][j][k]) % mod;
- 如果是下一行放一个,那么可能在j列中选择一个位置去放,也可能在k个位置中选择一个去放。
if (j >= 1) dp[i + 1][j - 1][k] = (dp[i + 1][j - 1][k] + dp[i][j][k] * j) % mod;
if (k >= 1) dp[i + 1][j + 1][k - 1] = (dp[i + 1][j + 1][k - 1] + dp[i][j][k] * k) % mod;
- 如果下一行可以放两个,那么可以在j列中选两个,或者在k列中选两个,或者j列中一个,k列中一个
if (j >= 2) dp[i + 1][j - 2][k] = (dp[i + 1][j - 2][k] + dp[i][j][k] * j * (j - 1) / 2) % mod;
if (k >= 2) dp[i + 1][j + 2][k - 2] = (dp[i + 1][j + 2][k - 2] + dp[i][j][k] * k * (k - 1) / 2) % mod;
if (j >= 1 && k >= 1) dp[i + 1][j][k - 1] = (dp[i + 1][j][k - 1] + dp[i][j][k] * j * k) % mod;
code
//dp[i][j][k] 表示现在放到了第i行,还有j列可以放1个,k列可以放两个
/* cinput
1 3
*/
/*output
7
*/
#include <bits/stdc++.h>
using namespace std;
#define int long long
inline int read() {
int k = 0, f = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) k = k * 10 + ch - '0';
return k * f;
}
const int maxn = 105, mod = 9999973;
int n, m, ans = 0, col[maxn], row[maxn], dp[maxn][maxn][maxn];
void dfs(int cur) {
if (cur == n * m + 1) return ans ++, void();
int y = cur % m;
if (y == 0) y = m;
int x = (cur - y) / m + 1;
if (row[x] == 2 || col[y] == 2) dfs(cur + 1);
else{
row[x]++, col[y]++, dfs(cur + 1);
row[x]--, col[y]--, dfs(cur + 1);
}
}
signed main() {
#ifdef local
freopen("in", "r", stdin);
#else
freopen("chess.in", "r", stdin);
freopen("chess.out", "w", stdout);
#endif
n = read(), m = read();
dp[0][0][m] = 1;
for (int i = 0; i <= n - 1; i++) {
for (int j = 0; j <= m; j++) {
for (int k = 0; k <= m - j; k++) {
if (!dp[i][j][k]) continue;
dp[i + 1][j][k] = (dp[i][j][k] + dp[i + 1][j][k]) % mod;
if (j >= 1) dp[i + 1][j - 1][k] = (dp[i + 1][j - 1][k] + dp[i][j][k] * j) % mod;
if (k >= 1) dp[i + 1][j + 1][k - 1] = (dp[i + 1][j + 1][k - 1] + dp[i][j][k] * k) % mod;
if (j >= 2) dp[i + 1][j - 2][k] = (dp[i + 1][j - 2][k] + dp[i][j][k] * j * (j - 1) / 2) % mod;
if (k >= 2) dp[i + 1][j + 2][k - 2] = (dp[i + 1][j + 2][k - 2] + dp[i][j][k] * k * (k - 1) / 2) % mod;
if (j >= 1 && k >= 1) dp[i + 1][j][k - 1] = (dp[i + 1][j][k - 1] + dp[i][j][k] * j * k) % mod;
}
}
}
int ans = 0;
for (int i = 0; i <= m; i++)
for (int j = 0; j <= m - i; j++)
ans = (ans += dp[n][i][j]) % mod;
cout << ans << endl;
}
T2 : 奇妙的 Fibonacci
。。。