题解 P3713 【[BJOI2017]机动训练】
StudyingFather · · 题解
容易看出,假如一共有
有没有觉得这个式子很眼熟?可以去看看 [NOI2009]管道取珠 这道题。
和那道题思路一样,我们将这个式子解释为两个人同时出发,在机动路径合法的前提下,走出相同地形序列的方案数。
我们设
接下来再设
记忆化搜索即可。
// Problem : P3713 [BJOI2017]机动训练
// Contest : Luogu
// URL : https://www.luogu.com.cn/problem/P3713
// Memory Limit : 250 MB
// Time Limit : 2000 ms
// Powered by CP Editor (https://github.com/cpeditor/cpeditor)
#include <cstdio>
#include <cstring>
#include <vector>
#define MOD 1000000009
using namespace std;
int f[5][5][5][5],g[35][35][35][35];
int m,n;
char s[35][35];
vector<pair<int,int> > a,b;
int dp(int x,int y,int r,int c)
{
if(s[x][y]!=s[r][c])return 0;
if(x<1||x>m||y<1||y>n||r<1||r>m||c<1||c>n)return 0;
if(~g[x][y][r][c])return g[x][y][r][c];
int ans=1;
for(auto i:a)
for(auto j:b)
{
int dx=i.first,dy=i.second,dr=j.first,dc=j.second;
ans=(ans+dp(x+dx,y+dy,r+dr,c+dc))%MOD;
}
return g[x][y][r][c]=ans;
}
int dfs(int x,int y,int p,int q)
{
if(~f[x+1][y+1][p+1][q+1])
return f[x+1][y+1][p+1][q+1];
a.clear(),b.clear();
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.emplace_back(i,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.emplace_back(i,j);
memset(g,-1,sizeof(g));
int ans=0;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
for(int r=1;r<=m;r++)
for(int c=1;c<=n;c++)
ans=(ans+dp(i,j,r,c))%MOD;
f[x+1][y+1][p+1][q+1]=f[p+1][q+1][x+1][y+1]=ans;
f[-x+1][-y+1][-p+1][-q+1]=f[-p+1][-q+1][-x+1][-y+1]=ans;
return ans;
}
int calc(int x,int y)
{
int ans=0;
ans=(ans+dfs(x,y,1,1))%MOD;
ans=(ans+dfs(x,y,1,-1))%MOD;
ans=(ans+dfs(x,y,-1,1))%MOD;
ans=(ans+dfs(x,y,-1,-1))%MOD;
ans=(ans-dfs(x,y,1,0)+MOD)%MOD;
ans=(ans-dfs(x,y,-1,0)+MOD)%MOD;
ans=(ans-dfs(x,y,0,1)+MOD)%MOD;
ans=(ans-dfs(x,y,0,-1)+MOD)%MOD;
return ans;
}
int main()
{
memset(f,-1,sizeof(f));
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++)
scanf("%s",s[i]+1);
int ans=0;
ans=(ans+calc(1,1))%MOD;
ans=(ans+calc(1,-1))%MOD;
ans=(ans+calc(-1,1))%MOD;
ans=(ans+calc(-1,-1))%MOD;
ans=(ans-calc(1,0)+MOD)%MOD;
ans=(ans-calc(-1,0)+MOD)%MOD;
ans=(ans-calc(0,1)+MOD)%MOD;
ans=(ans-calc(0,-1)+MOD)%MOD;
printf("%d\n",ans);
return 0;
}