迷宫是一个n*m的字符矩阵。
小明在这个矩阵的左上角,只能向下和向右走,去和在矩阵右下角的小芳会合。
小明必须将他走过的路径上的,经过的字符收集起来。如果到右下角时他收集到的这些字符连在一起是回文的,那么他就能够走出这个迷宫,否则他就会掉进陷阱出不来。
小明想知道有多少条路径能够让他走出这个迷宫。由于答案可能很大,请对1000000007取模。
输入输出格式
输入格式:第一行两个整数n和m。
接下来n行,每行m个字符表示这个矩阵,全部均为小写字母
输出格式:输出一行一个整数表示答案
输入输出样例
输入样例#1:
3 4 aaab baaa abba
输出样例#1:
3
说明
n,m<=500
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
const int dx[2][2]={{1,0},{-1,0}};
const int dy[2][2]={{0,1},{0,-1}};
const int MOD=1000000007;
int n,m;
int a[505][505],dp[2][505][505],ans=0; //dp[0,1][i][j] 表示第一个人走到第i行,第二个人走到第j行
int main()
{
int i,j,k,i1,i2,MAX_k;
string ch;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++){
cin>>ch;
for(j=0;j<m;j++){
a[i][j+1]=(int)(ch[j]-'a');
}
}
if(a[1][1]==a[n][m]){
dp[1][1][n]=1;
}
else{
cout<<0<<endl;
return 0;
}
MAX_k=(n+m)>>1;
for(k=1;k<MAX_k;k++){ //枚举对角线
memset(dp[(k+1)&1],0,sizeof(dp[(k+1)&1])); //滚动数组初始化
int MAX_i1=min(k,n);
for(i1=max(1,k-m+1);i1<=MAX_i1;i1++){
int MIN_i2=max(i1,n+1-MAX_i1);
for(i2=n+1-max(1,k-m+1);i2>=MIN_i2;i2--){
int j1=k-i1+1,j2=n+m-k-i2+1;
// cout<<k<<' '<<i1<<j1<<' '<<i2<<j2<<endl;
for(i=0;i<2;i++){
for(j=0;j<2;j++){
int nx1=i1+dx[0][i],ny1=j1+dy[0][i];
int nx2=i2+dx[1][j],ny2=j2+dy[1][j];
// cout<<nx1<<' '<<ny1<<' '<<nx2<<' '<<ny2<<' '<<"gg"<<endl;
if(nx1>n||ny1>m||nx2<1||ny2<1||nx1>nx2||ny1>ny2||a[nx1][ny1]!=a[nx2][ny2]) continue;
dp[(k+1)&1][nx1][nx2]=(dp[(k+1)&1][nx1][nx2]+dp[k&1][i1][i2])%MOD;
// cout<<nx1<<' '<<ny1<<' '<<nx2<<' '<<ny2<<' '<<i1<<i2<<' '<<dp[(k+1)&1][nx1][nx2]<<"gg"<<endl;
}
}
}
}
}
if((n+m)&1){
for(i=1;i<=n;i++){
ans=(ans+dp[MAX_k&1][i][i])%MOD;
ans=(ans+dp[MAX_k&1][i][i+1])%MOD;
}
}
else{
for(i=1;i<=n;i++){
ans=(ans+dp[MAX_k&1][i][i])%MOD;
}
}
cout<<ans<<endl;
return 0;
}