晚间测试 1

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

。。。

posted @ 2020-10-12 08:25  hyskr  阅读(99)  评论(1编辑  收藏  举报