不想写这篇的,毕竟看不懂英文,抱着看题意的想法去看了一下题解,一下子没忍住就全看了,还是算常规棋盘dp吧
给个链接:http://www.cnblogs.com/AOQNRMGYXLMV/p/4753881.html
总结一下就好了:
1.对于棋盘dp还有步数作为状态的考虑只储存横坐标然后递推出纵坐标可以优化一位下来
2.对于要求两边值一样的问题维护两个指针分别从两头向中间一起走
#include<cstdio>
#include<cstring>
#include<iostream>
#define add(a,b) (a+b>=Mod?a=a+b-Mod:a=a+b)
using namespace std;
const int Mod=1000000007;
const int maxn=510;
int f[2][maxn][maxn],n,m,vv;
char mat[maxn][maxn];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%s",mat[i]+1);
int pos=1;
if(mat[1][1]!=mat[n][m]){puts("0");return 0;}
f[1][1][n]=1;
for(int i=2;i<=n+m>>1;i++){//其实是n+m-1+1>>1 有一些细微的差别
pos^=1;
memset(f[pos],0,sizeof(f[pos]));
for(int x1=1;x1<=i;x1++){
for(int x2=n;x2>=n-i+1;x2--){
int y1=i-x1+1;
int y2=m+n+1-i-x2;
if(mat[x1][y1]==mat[x2][y2]){
add(f[pos][x1][x2],f[pos^1][x1][x2]);
add(f[pos][x1][x2],f[pos^1][x1-1][x2+1]);
add(f[pos][x1][x2],f[pos^1][x1][x2+1]);
add(f[pos][x1][x2],f[pos^1][x1-1][x2]);
}
}
}
}
int ans=0;
if((n+m)&1){//m+n-1^1 偶数
for(int i=1;i<=n;i++)add(ans,f[pos][i][i]),add(ans,f[pos][i][i+1]);
}else{
for(int i=1;i<=n;i++)add(ans,f[pos][i][i]);
}
printf("%d",ans);
return 0;
}