题意:给定一个 n ∗ m n*m n∗m 的地图,地图上每个格子有一个小写的英文字母,起点为 ( 1 , 1 ) (1,1) (1,1) ,终点为 ( n , m ) (n,m) (n,m) ,且每一步的移动只能往右移一格或者往下移一格。求所有从起点到终点的路径,经过的格子按顺序能组成回文串的路径个数。
思路:由于回文串的对称性,可以考虑同时从起点和终点出发,一个往右或下移动,一个往左或上移动。这样状态则为
(
x
1
,
y
1
,
x
2
,
y
2
)
(x1,y1,x2,y2)
(x1,y1,x2,y2) ,但是这样会超出内存限制。
由于是同时移动,所以两个点经过的步数相同,而已知步数和横坐标,就可以求出纵坐标,所以把状态进一步化简得
(
s
t
e
p
,
x
1
,
x
2
)
(step,x1,x2)
(step,x1,x2) ,但是这样还是会超出内存限制,所以就用滚动数组去掉
s
t
e
p
step
step 这一维即可,之后便是一般的
d
p
dp
dp 过程。
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
using namespace std;
const int mod = 1e9 + 7;
int n, m;
char a[505][505] = {};
int dp[2][505][505] = {};//表示当前某个状态的方法数
inline void AC()
{
cin >> n >> m;
for (int i = 1; i <= n; ++i)
{
getchar();
for (int j = 1; j <= m; ++j)
a[i][j] = getchar();
}
if (a[1][1] != a[n][m])
{
printf("0");
return;
}
dp[1][1][n] = 1;
for (int step = 2; step * 2 <= n + m - 1; ++step)
{
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
dp[step % 2][i][j] = 0;
for (int x1 = 1; x1 <= step && x1 <= n; ++x1)
{
int y1 = step - x1 + 1;
if (y1 < 1 || y1 > m)
continue;
for (int x2 = 1; x2 <= step && x2 <= n; ++x2)
{
int y2 = step - x2 + 1;
x2 = n - x2 + 1;
y2 = m - y2 + 1;
if (y2 < 1 || y2 > m || a[x1][y1] != a[x2][y2])
{
x2 = n + 1 - x2;
continue;
}
(dp[step % 2][x1][x2] += dp[1 - step % 2][x1 - 1][x2]) %= mod;
(dp[step % 2][x1][x2] += dp[1 - step % 2][x1 - 1][x2 + 1]) %= mod;
(dp[step % 2][x1][x2] += dp[1 - step % 2][x1][x2 + 1]) %= mod;
(dp[step % 2][x1][x2] += dp[1 - step % 2][x1][x2]) %= mod;
//printf("step:%d [%d,%d] [%d,%d]\n", step, x1, y1, x2, y2);
x2 = n + 1 - x2;
}
}
}
int ans = 0;
int step = (n + m - 1) >> 1;
if ((n + m - 1) & 1)
{
for (int x = 1; x <= n; ++x)
{
(ans += dp[step % 2][x][x + 1]) %= mod;
(ans += dp[step % 2][x - 1][x + 1]) %= mod;
(ans += dp[step % 2][x - 1][x]) %= mod;
(ans += dp[step % 2][x][x]) %= mod;
}
printf("%d\n", ans);
return;
}
for (int x1 = 1; x1 <= step; ++x1)
{
int y1 = step - x1 + 1;
if (y1 < 1 || y1 > m)
continue;
for (int x2 = 1; x2 <= step; ++x2)
{
int y2 = step - x2 + 1;
x2 = n - x2 + 1;
y2 = m - y2 + 1;
if (y2 < 1 || y2 > m || !((x1 == x2 && y2 == y1 + 1) || (y1 == y2 && x2 == x1 + 1)))
{
x2 = n + 1 - x2;
continue;
}
(ans += dp[step % 2][x1][x2]) %= mod;
x2 = n + 1 - x2;
}
}
printf("%d\n", ans);
}
int main()
{
AC();
return 0;
}