// Codeforces #316 E Pig and Palindromes
//
// 题目大意:
//
// 给你一张地图,n*m每个点是一个字母,现在从(0,0)出发,
// 每次只能往右或者往下走,求走到(n-1,m-1)形成回文串的方法数.
//
// 解题思路:
//
// 动态规划.首先.如果起点和终点的字母不相同,那么肯定
// 不能形成回文串,直接输出0.对于能形成回文串.我们设状态
// d(step,i,j)表示走了step步,从第0行走到i行,第n-1行走到j行的
// 能形成回文串的方法数.
// 1)从左上方只能往右,或者下方走
// 2)从右下方只能往左,或者上方走
// 我们采用刷表法从d(step,i,j)分别对
//
// d(step+1,i+1,j) 下,左
// d(step+1,i+1,j-1) 下,上
// d(step+1,i,j); 右,左
// d(step+1,i,j-1); 右,上
//
// 由于内存的限制,而状态只依赖于上一步的状态.则我们只需要step开2维即可
// 或者用一个temp数组暂时存储.
//
// 最后的结果也要分所形成的回文串的奇偶来判断.
//
// 回文串奇数:
//
// 这样一定是到了一个共同的字母,即中间的字母就相遇了.即走到了同一行
// 累加d(i,i).输出结果.
//
// 回文串偶数:
//
// 这样最后一定是双方同时走一步正好相邻.换而言之相遇的结果只能是左上方
// 走到某个点x(i,j),同时右下方的点走到了x的右边一个或者下边一个.这时候判断
// 并做累加就好了.
//
// 感悟:
//
// 这道题,虽然题目的意思很简单,但是对于我看来,实在是太复杂了,哎,dp的弱才啊
// 我开始看的是红名爷的代码,有很多疑惑的地方,最后MY一眼看出就是SB题目,给我讲了
// 状态,转移.还有边界等一系列.可以说是手把手的教.哎,卡了这么久,总算是能够真正
// 的理解红名爷还有MY的思路了.差距就是这么大啊,小子在此感谢MY还有红名爷~~~
// 哎,不说什么了,继续加油吧!FIGHTING
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll MOD = 1e9 + 7;
const int maxn = 508;
char g[maxn][maxn];
ll d[maxn][maxn];
ll tmp[maxn][maxn];
int n,m;
bool ok(int x1,int y1,int x2,int y2){
if (x1<n && y1<m && x2>=0 && y2>=0 && g[x1][y1] == g[x2][y2])
return true;
return false;
}
void add(ll &x ,ll y){
x += y;
if (x>=MOD)
x -= MOD;
}
void print(){
for (int i=0;i<n;i++){
for (int j=0;j<m;j++)
cout << d[i][j] << " ";
cout << endl;
}
}
void input(){
for (int i=0;i<n;i++)
scanf("%s",g[i]);
if (g[0][0]!=g[n-1][m-1]){
puts("0");
return ;
}
memset(d,0,sizeof(d));
memset(tmp,0,sizeof(tmp));
d[0][n-1] = 1;
int s = n + m - 2;
for (int step = 0; step < s/2;step++){
for (int x0 = 0;x0 < n && step - x0 >=0;x0++){
int y0 = step - x0;
for (int x1 = 0;x1 < n && s - step - x1>=0 ;x1++){
int y1 = s - step - x1;
if (ok(x0+1,y0,x1-1,y1)){
add(tmp[x0+1][x1-1],d[x0][x1]);
}
if (ok(x0+1,y0,x1,y1-1)){
add(tmp[x0+1][x1],d[x0][x1]);
}
if (ok(x0,y0+1,x1-1,y1)){
add(tmp[x0][x1-1],d[x0][x1]);
}
if (ok(x0,y0+1,x1,y1-1)){
add(tmp[x0][x1],d[x0][x1]);
}
}
}
for (int i=0;i<n;i++)
for (int j=0;j<n;j++){
d[i][j] = tmp[i][j];
tmp[i][j] = 0;
}
}
if (n + m - 1 & 1){
ll ans = 0;
for (int i=0;i<n;i++){
add(ans,d[i][i]);
}
printf("%I64d\n",ans);
}else {
ll ans = 0;
s /= 2;
for (int i=0;i<n;i++){ // i表示走到了i行
if (s - i + 1 < m && g[i][s-i]==g[i][s-i+1]) //判断走到该点的右边是否与之相同
add(ans,d[i][i]);
if (i + 1 < n && g[i][s-i] == g[i+1][s-i]) // 判断走到该点的下边是否与之相同
add(ans,d[i][i+1]);
}
printf("%I64d\n",ans);
}
}
int main(){
//freopen("1.txt","r",stdin);
while(scanf("%d%d",&n,&m)!=EOF){
input();
}
return 0;
}
Codeforces #316 E Pig and Palindromes DP
最新推荐文章于 2022-04-10 01:42:22 发布