【动态规划】Codeforces 570E Pig and Palindromes

通道

题意:n*m的字符矩阵,每次只能向右或向下走,求从(1,1)走到(n,m)的路径中有多少个回文。

思路:我们可以从两端开始走。dp[i][j][k]:分别走i步(也可以理解为半径为i),A到达j行,B到达k行的回文数。走的半径逐渐减少即可。

可以知道第x1行只能由前一次的x1行或x1+1行转移,第x2行只能由前一次的x2-1或x2转移,所有就有四种情况。

dp[i][x1][x2] = (dp[i-1][x1][x2] + dp[i-1][x1 + 1][x2] + dp[i-1][x1][x2 - 1] + dp[i-1][x1 + 1][x2 - 1]) % MOD;

代码:

#include <cstdio>
#include <cstring>

typedef long long ll;

const int MAX_N = 507;
const int MOD = 1000000007;

int n, m;
char s[MAX_N][MAX_N];
ll dp[2][MAX_N][MAX_N];

int main() {
    scanf("%d %d", &n, &m);
    for (int i = 0; i < n; ++i)
        scanf("%s", s[i]);
    bool cur = 0;
    int longest = (n + m) / 2 - 1;
    for (int x1 = 0; x1 < n && x1 <= longest; ++x1) {
        int y1 = longest - x1;
        for (int x2 = 0; x2 < n; ++x2) {
            int y2 = m - 1 - (longest - (n - 1 - x2));
            if (x1 <= x2 && y1 <= y2 && s[x1][y1] == s[x2][y2]) 
                dp[0][x1][x2] = 1;
        }
    }
    for (int i = longest - 1; i >= 0; --i) {
        cur = !cur;
        memset(dp[cur], 0, sizeof dp[cur]);
        for (int x1 = 0; x1 <= i && x1 < n; ++x1) {
            int y1 = i - x1;
            for (int x2 = 0; x2 < n; ++x2) {
                int y2 = m - 1 - (i - (n - 1 - x2));
                if (x1 <= x2 && y1 <= y2 && s[x1][y1] == s[x2][y2]) 
                    dp[cur][x1][x2] = (dp[!cur][x1][x2] + dp[!cur][x1 + 1][x2] + dp[!cur][x1][x2 - 1] + dp[!cur][x1 + 1][x2 - 1]) % MOD;
            }
        }
    }
    printf("%I64d\n", dp[cur][0][n - 1]);
    return 0;
}
View Code

 

posted @ 2015-08-14 13:14  mithrilhan  阅读(192)  评论(0编辑  收藏  举报