zoukankan      html  css  js  c++  java
  • 2014百度之星初赛第二轮解题报告:chess

    chess
    时间限制:3s 内存限制: 65536K
    问题描述
    小度和小良最近又迷上了下棋。棋盘一共有N行M列,我们可以把左上角的格子定为(1,1),右下角的格子定为(N,M)。在他们的规则中,“王”在棋盘上的走法遵循十字路线。也就是说,如果“王”当前在(x,y)点,小度在下一步可以移动到(x + 1,y),(x − 1,y),(x,y + 1),(x,y − 1),(x + 2,y),(x − 2,y),(x,y + 2),(x,y − 2)这八个点中的任意一个。

    C497-3001-1.jpg                               
    图1 黄色部分为棋子所控制的范围
    小度觉得每次都是小良赢,没意思。为了难倒小良,他想出了这样一个问题:如果一开始“王”在(x0,y0)点,小良对“王”连续移动恰好K步,一共可以有多少种不同的移动方案?两种方案相同,当且仅当它们的K次移动全部都是一样的。也就是说,先向左再向右移动,和先向右再向左移动被认为是不同的方案。
    小良被难倒了。你能写程序解决这个问题吗?
    输入:
    输入包括多组数据。输入数据的第一行是一个整数T(T≤10),表示测试数据的组数。
    每组测试数据只包括一行,为五个整数N,M,K,x0,y0(1≤N,M,K≤1000,1≤x0≤N,1≤y0≤M)
    输出:
    对于第k组数据,第一行输出Case #k:,第二行输出所求的方案数。由于答案可能非常大,你只需要输出结果对9999991取模之后的值即可。
    样例输入:
    2
    2 2 1 1 1
    2 2 2 1 1

    样例输出:
    Case #1:
    2
    Case #2:
    4

    解题报告:
             最直接是使用O(NMK)DP方式,用dp[x][y][k]表示第k步跳转到(x,y)的方案数,然后逐步递推。但是由于时间复杂度比较高,所以需要考虑优化的方式。
             考虑一次移动k步的方案,可以发现行和列的移动方式是独立的。因此可以先分别求出在行和列上移动的方案数,再枚举k步里有多少步分别是纵向和横向移动的
             假设A[x][k]表示起始横坐标为x0移动k步到横坐标为x的方案数,通过递归可求得每个A[x][k],则可求得纵向移动k步的方案数V[k] = sum(A[x][k] 1<=x<=n)
    假设B[y][k]表示起始纵坐标为y0,移动k步到纵坐标为y的方案数,通过递归可求得每个A[y][k],则可求得横向移动k步的方案数H[k] = sum(B[y][k] 1<=y<=m)
             最终答案为sum(c(K,i)*V*H[K-i]0<=i<=K)。总体复杂度可以降低到O(NK) + O(MK)


    解题代码:

    #include <cstdio>
    #include <cstring>
    
    const int N = 1000 + 1;
    const int MOD = 9999991;
    
    int n, m, k, x0, y0;
    int C[N][N], buffer[N][N], horizonal[N], vertical[N];
    
    void solve(int *number, int n, int x0) {
        memset(buffer, 0, sizeof(buffer));
        buffer[0][x0] = 1;
        for (int i = 1; i <= k; ++ i) {
            for (int j = 1; j <= n; ++ j) {
                if (j - 1 >= 1) {
                    (buffer[j] += buffer[i - 1][j - 1]) %= MOD;
                }
                if (j - 2 >= 1) {
                    (buffer[j] += buffer[i - 1][j - 2]) %= MOD;
                }
                if (j + 1 <= n) {
                    (buffer[j] += buffer[i - 1][j + 1]) %= MOD;
                }
                if (j + 2 <= n) {
                    (buffer[j] += buffer[i - 1][j + 2]) %= MOD;
                }
            }
        }
        for (int i = 0; i <= k; ++ i) {
            number = 0;
            for (int j = 1; j <= n; ++ j) {
                (number += buffer[j]) %= MOD;
            }
        }
    }
    
    int main() {
        C[0][0] = 1;
        for (int i = 1; i < N; ++ i) {
            C[0] = 1;
            for (int j = 1; j <= i; ++ j) {
                C[j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
            }
        }
        int test_count;
        int T = 1;
        scanf("%d", &test_count);
        while (test_count --) {
            scanf("%d%d%d%d%d", &n, &m, &k, &x0, &y0);
            solve(vertical, n, x0);
            solve(horizonal, m, y0);
            int answer = 0;
            for (int i = 0; i <= k; ++ i) {
                (answer += (long long)C[k] * horizonal % MOD * vertical[k - i] % MOD) %= MOD;
            }
            printf("Case #%d:
    %d
    ", T++, answer);
        }
        return 0;
    }


  • 相关阅读:
    [CF837B] Flag of Berland(乱写)
    [Uva12563] Jin Ge Jin Qu hao (完全背包,dp)
    [BZOJ2818] Gcd (数论,欧拉函数,线性筛)
    [CF777E] Hanoi Factory(贪心,栈)
    [CF777D] Cloud of Hashtags(贪心,二分)
    [CF777C] Alyona and Spreadsheet(dp)
    [BZOJ2440][中山市选2011]完全平方数(莫比乌斯函数,二分)
    [CF821C] Okabe and Boxes(模拟,栈)
    Codeforces Round #363 (Div. 2)->B. One Bomb
    Codeforces Round #363 (Div. 2)->A. Launch of Collider
  • 原文地址:https://www.cnblogs.com/hosealeo/p/4190500.html
Copyright © 2011-2022 走看看