BZOJ4859 BJOI2017机动训练

Problem

BZOJ

Solution

Salamander安利的一道题目。。思路很神的一道题目

对于平方,我们可以转化为选两条路径都为某个方案的方案数。注意到这个机动路径的定义,其实在确定了x,y之后,路径就是只能朝一个象限(虽然还包括了坐标轴)的方向走,那么我们不妨设g[x1][y1][x2][y2]表示第一条路径的方向向量为(x1,y1),(x2,y2)的方案数。然后我们可以记忆化搜索,f[x][y][xx][yy]在当前路径方案下,表示第一条路径从(x,y)出发,第二条路径从(xx,yy)出发的方案数。注意到坐标轴的方向会被重复计算,所以要减去。
注意到g的答案是可以重复利用的,因为有些方案是一样的,因此只需要搜 8 8 4 = 16 次。时间复杂度是 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;
}

猜你喜欢

转载自blog.csdn.net/as_a_kid/article/details/80718813
今日推荐