【动态规划】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; }