HDU 5617 Jam's maze 巧妙DP

题意:给你一个字符矩阵,从(1,1)到(n,n)有很多种走法,每一种走法形成一个字符串,问有多少种走法形成的字符串是回文的

分析:(粘贴BC题解)

的是回文串,有人会想到后缀数组自动机马拉车什么的,其实只要求方案数很多,所以我们应该想到动态规划,首先是状态的定义,我们可以想着从(1,1)(1,1)(n,n)(n,n)开始走,然后走到相遇。所以我们定义状态可以定义为f[x_1][y_1][x_2][y_2]f[x1​​][y1​​][x2​​][y2​​]表示所对应的两个点(x_1,y_1)(x_2,y_2)(x1​​,y1​​)(x2​​,y2​​),这样的话考虑到数据的范围,显然会爆空间,然后我们想一想就是走多少步和知道x_1,x_2x1​​,x2​​的位置,就可以确定y_1,y_2y1​​,y2​​的位置。于是我们把状态定义为f[i][x_1][x_2]f[i][x1​​][x2​​]即可,状态转移很显然,如果相等的话把四个方向都扫一下即可。因为还是会爆空间,所以我们把第一维改成滚动数组就解决问题

注:其实这个题解的意思就是从1,1 和n,n 开始按距离  斜着更新,最后统计相遇的地方,相遇显然就是dp[n-1][i][i]

难点就是斜着更新不好想,还有就是滚动数组的空间优化

然后附上丑的代码;

#pragma comment(linker,"/STACK:102400000,102400000")
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <cmath>
#include <climits>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <list>
#include <bitset>
#include <vector>
#include <cassert>
using namespace std;
const int maxn=505;
const int mod=5201314;
int dp[2][maxn][maxn];
char s[maxn][maxn];
int T,n;
void add(int &x,int y)
{
    x+=y;
    if(x>mod)x-=mod;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
         scanf("%s",s[i]+1);
        if(s[1][1]!=s[n][n])
        {
           printf("0\n");
           continue;
        }
        int cur=0;
        memset(dp[cur],0,sizeof(dp[cur]));
        dp[cur][1][n]=1;
        for(int i=1;i<n;++i)
        {
          cur^=1;
          memset(dp[cur],0,sizeof(dp[cur]));
          for(int x1=1;x1<=i+1;++x1)
          {
             for(int x2=n;x2>=n-i;--x2)
             {
                  int y1=i+2-x1;
                  int y2=n*2-x2-i;
                  if(s[x1][y1]!=s[x2][y2])continue;
                  add(dp[cur][x1][x2],dp[cur^1][x1][x2]);
                  add(dp[cur][x1][x2],dp[cur^1][x1][x2+1]);
                  add(dp[cur][x1][x2],dp[cur^1][x1-1][x2]);
                  add(dp[cur][x1][x2],dp[cur^1][x1-1][x2+1]);
             }
          }
        }
        int ans=0;
        for(int i=1;i<=n;++i)
          add(ans,dp[cur][i][i]);
       printf("%d\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2016-02-02 13:25  shuguangzw  阅读(239)  评论(0编辑  收藏  举报