Codeforces Round #316 (Div. 2) 回文路径(DP)

题目链接

题意是,给出一个n * m的字母矩阵,从(1, 1)点走到(n, m)点,经过路径的上的每一个字母按顺序会排成一个字符串。现在希望排成的字符串是回文串,问这样的路径会有多少条,结果对1e9 + 7取模。

这是一个对官方题解从开始到放弃的过程,这场的上一题感觉官解写得短小精悍,然后这一题,是不是短小精悍不知道,反正是真看不下去。看了这篇博客懂了不少。

https://blog.csdn.net/u010660276/article/details/47700441

大的思路看这个就很棒了,补充一下我在理解上的一点障碍。虽然是只存了两个点的横坐标,但是由于step的限制,其实dp数组是连带着纵坐标一起存下来的,这个意识一定要弄清楚,不然会连带着想不清为什么可以这么递推、为什么不会多出来答案。可以在理解思路的时候把这个dp数组想象成是有纵坐标的,然后递推过来就会清晰一些。另外,这篇题解里面代码的递推部分注释感觉有问题,向哪里向哪里不太好理解,可以忽略它的注释。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 550;
const int _n = 1e9 +7;
int n, m;
char s[mx][mx];
ll dp[2][mx][mx];//上一个状态or当前状态 从(1, 1)开始的点的横坐标 (n, m)开始的点的横坐标
inline ll add(ll a, ll b, ll c, ll d){
    return (a + b + c + d) % _n;
}
int main()
{
    cin >> n >> m;
    for(int i = 1; i <= n; i++){
        scanf("%s", s[i] + 1);
    }
    int cur = 0;
    dp[cur][1][n] = (s[1][1] == s[n][m]);
    for(int step = 1; step <= ((n + m - 2) >> 1); step++){
        int lst = cur;
        cur ^= 1;
        for(int x1 = 1; x1 <= n; x1++)
        for(int x2 = 1; x2 <= n; x2++){
            dp[cur][x1][x2] = 0;
        }
        for(int x1 = 1; x1 <= n && x1 <= 1 + step; x1++)
        for(int x2 = n; x2 >= 1 && x2 >= n - step; x2--){
            int y1 = 1 + step - (x1 - 1);
            int y2 = n - x2 + m - step;
            if(s[x1][y1] != s[x2][y2]) continue;
            dp[cur][x1][x2] = add(dp[lst][x1][x2], dp[lst][x1][x2+1],
                                  dp[lst][x1-1][x2], dp[lst][x1-1][x2+1]);
        }
    }
    ll ans = 0;
    for(int i = 1; i <= n; i++){
        ans += dp[cur][i][i];
        ans %= _n;
    }
    if((m + n) & 1){
        for(int i = 1; i <= n; i++){
            ans += dp[cur][i][i+1];
            ans %= _n;
        }
    }
    cout << ans << endl;
	return 0;
}
 
 
 

猜你喜欢

转载自blog.csdn.net/xuzonghao/article/details/88935947