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;
}

猜你喜欢

转载自www.cnblogs.com/shandongs1/p/9451117.html