2014百度之星初赛第二轮解题报告:chess

来源:互联网 发布:mac 删除软件 编辑:程序博客网 时间:2024/05/02 00:17

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:\n%d\n", T++, answer);    }    return 0;}


0 0
原创粉丝点击