https://www.luogu.org/problem/show?pid=3126
考虑dp,从两头走到中间。
f[i][j][k][l]表示从左上角走到(i,j),从右下角走到(k,l),路径长度相等,所经过路径相同的方案数。
方程不再赘述。
考虑步数要相同,所以只要枚举步数和行就好。
f[i][j][k]表示第一个点在第j行,第2个点在第k行,走i步的方案数。
所以得出方程f[i][j][k]=(f[i-1][j-1][k]+f[i-1][j][k+1]+f[i-1][j-1][k+1]+f[i-1][j][k])%mod;
然后显然第一维滚动数组优化。
#include<cstdio> #include<cstring> #define clz 1000000007 int n,m; long long f[2][510][510]; char s[510][510]; int Max(int a,int b){ return a>b?a:b; } int Min(int a,int b){ return a<b?a:b; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%s",s[i]+1); } if(s[1][1]!=s[n][m]) return !puts("0"); f[0][1][n]=1; bool I=1; for(int i=1;i<=(n+m-2)>>1;i++){ memset(f[I],0,sizeof(f[I])); for(int j=1;j<=Min(i+1,n);j++){ for(int k=n;k>=j&&k>=Max(n-i,1);k--){ int p1=i-j+2,p2=m-i+n-k; if(s[j][p1]==s[k][p2]){ f[I][j][k]=(f[I^1][j-1][k]+f[I^1][j][k+1]+f[I^1][j-1][k+1]+f[I^1][j][k])%clz; } } } I^=1; } long long ans=0; I^=1; if((n+m)%2==1){ for(int i=1;i<=n;i++) ans=(ans+f[I][i][i]+f[I][i][i+1])%clz; } else{ for(int i=1;i<=n;i++) ans=(ans+f[I][i][i])%clz; } printf("%lld\n",ans%clz); return 0; }
时间: 2024-10-09 20:48:25