Problem
Solution
Salamander安利的一道题目。。思路很神的一道题目
对于平方,我们可以转化为选两条路径都为某个方案的方案数。注意到这个机动路径的定义,其实在确定了x,y之后,路径就是只能朝一个象限(虽然还包括了坐标轴)的方向走,那么我们不妨设g[x1][y1][x2][y2]表示第一条路径的方向向量为(x1,y1),(x2,y2)的方案数。然后我们可以记忆化搜索,f[x][y][xx][yy]在当前路径方案下,表示第一条路径从(x,y)出发,第二条路径从(xx,yy)出发的方案数。注意到坐标轴的方向会被重复计算,所以要减去。
注意到g的答案是可以重复利用的,因为有些方案是一样的,因此只需要搜
8∗84=16
8
∗
8
4
=
16
次。时间复杂度是
O(16×n4)
O
(
16
×
n
4
)
,稍微注意一下常数即可。。
Code
#include <cstring>
#include <cstdio>
#define rg register
using namespace std;
const int mod=1000000009;
int n,m,ans,cnt1,cnt2,f[31][31][31][31],g[3][3][3][3],a[2][10],b[2][10];
char s[31][31];
inline int pls(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
int dp(int x,int y,int p,int q)
{
if(s[x][y]!=s[p][q]) return 0;
if(x<1||x>n||p<1||p>n||y<1||y>m||q<1||q>m) return 0;
if(~f[x][y][p][q]) return f[x][y][p][q];
int sum=1;
for(int i=1;i<=cnt1;i++)
for(int j=1;j<=cnt2;j++)
sum=pls(sum,dp(x+a[0][i],y+a[1][i],p+b[0][j],q+b[1][j]));
return f[x][y][p][q]=sum;
}
int solve(int x,int y,int p,int q)
{
if(~g[x+1][y+1][p+1][q+1]) return g[x+1][y+1][p+1][q+1];
cnt1=cnt2=0;
for(int i=-1;i<=1;i++)
if(!i||i==x)
for(int j=-1;j<=1;j++)
if((i||j)&&(!j||j==y))
a[0][++cnt1]=i,a[1][cnt1]=j;
for(int i=-1;i<=1;i++)
if(!i||i==p)
for(int j=-1;j<=1;j++)
if((i||j)&&(!j||j==q))
b[0][++cnt2]=i,b[1][cnt2]=j;
memset(f,0xff,sizeof(f));
int sum=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(rg int r=1,w;r<=n;r++)
for(w=1;w<=m;w++)
sum=pls(sum,dp(i,j,r,w));
g[x+1][y+1][p+1][q+1]=g[p+1][q+1][x+1][y+1]=sum;
g[-x+1][-y+1][-p+1][-q+1]=g[-p+1][-q+1][-x+1][-y+1]=sum;
return sum;
}
int solve(int x,int y)
{
int res=0;
res=pls(res,solve(x,y,1,1));res=pls(res,solve(x,y,1,-1));
res=pls(res,solve(x,y,-1,1));res=pls(res,solve(x,y,-1,-1));
res=dec(res,solve(x,y,0,1));res=dec(res,solve(x,y,0,-1));
res=dec(res,solve(x,y,1,0));res=dec(res,solve(x,y,-1,0));
return res;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
memset(g,0xff,sizeof(g));
ans=pls(ans,solve(1,1));ans=pls(ans,solve(1,-1));
ans=pls(ans,solve(-1,1));ans=pls(ans,solve(-1,-1));
ans=dec(ans,solve(0,1));ans=dec(ans,solve(0,-1));
ans=dec(ans,solve(1,0));ans=dec(ans,solve(-1,0));
printf("%d\n",ans);
return 0;
}