题目描述
迷宫是一个 n*m的字符矩阵。 小明在这个矩阵的左上角,只能向下和向右走,去和在矩阵右下角的小芳会合。 小明必须将他走过的路径上的,经过的字符收集起来。如果到右下角时他收集到的这些
字符连在一起是回文的,那么他就能够走出这个迷宫,否则他就会掉进陷阱出不来。 小明想知道有多少条路径能够让他走出这个迷宫。由于答案可能很大,请对 1000000007取模。
输入格式:
第一行两个整数 n 和m。 接下来 n 行,每行m个字符表示这个矩阵
输出格式:
输出一行一个整数表示答案
输入样例#1:
3 4
aaab
baaa
abba
输出样例#1:
3
数据范围
对于 20%的数据,满足 n∗m≤10 对于另外 10%的数据,满足字符都是 a 对于 70%的数据,满足 n,m≤60
对于 100%的数据,满足 n,m≤500
题解
dp
d[step][x1][x2]记录第step步从(0,0)走到(x1,y1) 且从(n-1,m-1)走到(x2,y2)的方法数
y可用step与x表示
d可用滚动数组优化
代码
#include<bits/stdc++.h>
#define F( i,a,b ) for( int i=(a);i<=(b);i++ )
#define F_2( i,a,b ) for( int i=(a);i>=(b);i-- )
#define N 507
#define M 10001
#define P 1000000007
#define LL long long
#define oo 0x7fffffff
using namespace std;
inline int read()
{
int f=1,s=0;
char ch=getchar();
while( ch>'9' || ch<'0' ) { if( ch=='-' ) f=-1; ch=getchar(); }
while( ch<='9' && ch>='0' ) { s=( s<<1 )+( s<<3 )+ch-'0'; ch=getchar(); }
return f*s;
}
const int dx[N]={ 0,1,0,-1,0 };
const int dy[N]={ 0,0,1,0,-1 };
int m,n,k;
int tot,ans,cnt,lab;
string a[N];
int d[2][N][N];
void dp()
{
d[lab][0][n-1]=1;
F( step,1,(m+n-2)/2 )
{
lab^=1;
int mini=min( n-1,step );
memset( d[lab],0,sizeof( d[lab] ) );
F( i,0,mini )
{
int maxj=max( 0,n-1-step );
F_2( j,n-1,maxj )
{
if( a[i][step-i]==a[j][m+n-2-step-j] )
{
d[lab][i][j]=( d[lab][i][j]+d[lab^1][i][j] )%P;
d[lab][i][j]=( d[lab][i][j]+d[lab^1][i][j+1] )%P;
if( i-1>=0 )
{
d[lab][i][j]=( d[lab][i][j]+d[lab^1][i-1][j] )%P;
d[lab][i][j]=( d[lab][i][j]+d[lab^1][i-1][j+1] )%P;
}
}
}
}
}
}
int main()
{
freopen( "treasure.in","r",stdin );
freopen( "treasure.out","w",stdout );
n=read();
m=read();
F( i,0,n-1 )
cin>>a[i];
dp();
int len=( m+n-2)/2;
len=min( len,n-1 );
F( i,0,n-1 )
ans=( ans+d[lab][i][i] )%P;
if( (n+m)%2 )
F( i,0,n-1 )
ans=( ans+d[lab][i][i+1] )%P;
cout<<ans<<endl;
return 0;
}