• 晚间测试 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

    。。。

  • 相关阅读:
    JAVA类型转换
    ASCII码表
    Java运算符的优先级(从高到低)
    Java内各种进制的表示
    java 标识符命名规则
    Java介绍(重要特点)
    多线程
    Mac&iOS之多线程--转自http://geeklu.com/2012/02/thread/
    00002-20180324-数组-列表
    00001-20180324-从列表中获取单个元素
  • 原文地址:https://www.cnblogs.com/hellohhy/p/13800765.html
Copyright © 2020-2023  润新知