51nod 1503
动态规划
$f[a][b][c][d]$ 表示从 $(1, 1)$ 走到 $(a, b)$ 和从 $(n, m)$ 走到 $(c, d)$ 的方案数
$f[a][b][c][d]$
$= f[a][b - 1][c][d + 1] + f[a][b - 1][c + 1][d] + f[a - 1][b][c + 1][d] + f[a - 1][b][c][d + 1]$
当然这里忽略了判断条件
时空爆炸
考虑如果知道的 $s = a + b, a, c$ 就可以推出 $d$
因此可以压掉一维,时间复杂度 $n ^ 3$
然而空间依旧爆炸
发现 $f[s][*][*]$ 只与 $f[s - 1][*][*]$ 有关
因此只开两个即可
抽离
$f[cur][x1][x2] = (f[cur][x1][x2] + f[cur ^ 1][x1][x2] + f[cur ^ 1][x1 - 1][x2] + f[cur ^ 1][x1][x2 + 1] + f[cur ^ 1][x1 - 1][x2 + 1]) % Mod$
最后 $Ans = \sum_{i = 1}^{n}f[cur][i][i]$
如果 $n + m$ 为奇数
$Ans += \sum_{i = 1}^{n} f[cur][i][i + 1]$
#include <bits/stdc++.h> const int N = 510, Mod = 1e9 + 7; long long f[2][N][N], n, m; char s[N][N]; int main() { std:: cin >> n >> m; for(int i = 1; i <= n; i ++) scanf("%s", s[i] + 1); if(s[1][1] != s[n][m]) { puts("0"); return 0; } int cur = 0; f[0][1][n] = 1; for(int k = 1; k <= (n + m - 2) / 2; k ++) { cur ^= 1; for(int i = 1; i <= n; i ++) for(int j = 1; j <= n; j ++) f[cur][i][j] = 0; for(int x1 = 1; x1 <= n && x1 - 1 <= k; x1 ++) { for(int x2 = n; x2 >= 1 && n - x2 <= k; x2 --) { int y1 = k + 2 - x1, y2 = n + m - k - x2; if(s[x1][y1] != s[x2][y2]) continue; f[cur][x1][x2] = (f[cur][x1][x2] + f[cur ^ 1][x1][x2] + f[cur ^ 1][x1 - 1][x2] + f[cur ^ 1][x1][x2 + 1] + f[cur ^ 1][x1 - 1][x2 + 1]) % Mod; } } } int Ans(0); for(int i = 1; i <= n; i ++) Ans = (Ans + f[cur][i][i]) % Mod; if((n + m) % 2) for(int i = 1; i <= n; i ++) Ans = (Ans + f[cur][i][i + 1]) % Mod; std:: cout << Ans; return 0; }