寻宝之后

迷宫是一个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;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值