hdu 4758 - Walk Through Squares(AC自动机+DP)现场赛

原创 2015年07月08日 15:26:15

Walk Through Squares

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 1046    Accepted Submission(s): 318


Problem Description

  On the beaming day of 60th anniversary of NJUST, as a military college which was Second Artillery Academy of Harbin Military Engineering Institute before, queue phalanx is a special landscape.
  
  Here is a M*N rectangle, and this one can be divided into M*N squares which are of the same size. As shown in the figure below:
  01--02--03--04
  || || || ||
  05--06--07--08
  || || || ||
  09--10--11--12
  Consequently, we have (M+1)*(N+1) nodes, which are all connected to their adjacent nodes. And actual queue phalanx will go along the edges.
  The ID of the first node,the one in top-left corner,is 1. And the ID increases line by line first ,and then by column in turn ,as shown in the figure above.
  For every node,there are two viable paths:
  (1)go downward, indicated by 'D';
  (2)go right, indicated by 'R';
  The current mission is that, each queue phalanx has to walk from the left-top node No.1 to the right-bottom node whose id is (M+1)*(N+1).
In order to make a more aesthetic marching, each queue phalanx has to conduct two necessary actions. Let's define the action:
  An action is started from a node to go for a specified travel mode.
  So, two actions must show up in the way from 1 to (M+1)*(N+1).

  For example, as to a 3*2 rectangle, figure below:
    01--02--03--04
    || || || ||
    05--06--07--08
    || || || ||
    09--10--11--12
  Assume that the two actions are (1)RRD (2)DDR

  As a result , there is only one way : RRDDR. Briefly, you can not find another sequence containing these two strings at the same time.
  If given the N, M and two actions, can you calculate the total ways of walking from node No.1 to the right-bottom node ?
 

Input
  The first line contains a number T,(T is about 100, including 90 small test cases and 10 large ones) denoting the number of the test cases.
  For each test cases,the first line contains two positive integers M and N(For large test cases,1<=M,N<=100, and for small ones 1<=M,N<=40). M denotes the row number and N denotes the column number.
  The next two lines each contains a string which contains only 'R' and 'D'. The length of string will not exceed 100. We ensure there are no empty strings and the two strings are different.
 

Output
  For each test cases,print the answer MOD 1000000007 in one line.
 

Sample Input
2 3 2 RRD DDR 3 2 R D
 

Sample Output
1 10
 

Source


题意:包含给定的两个字符串,并且能够从左上角到达右下角,有多少种走法

思路:构建AC自动机后,四维dp[x][y][i][j]表示有x个R,y个D,在树上的节点i,并且状态集为j的方案数,刚开始一直在纠结怎么保证从左上到右下,看了kuangbin大神的题解,恍然大悟

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=105*2;
const int maxm=105;
const int MOD=1e9+7;
const double INF=1e20;
const int SIGMA_SIZE=2;
int N,M;
int dp[maxm][maxm][maxn][4];
char s[maxm];
struct AC
{
    int ch[maxn][2];
    int val[maxn];
    int fail[maxn];
    int sz;
    void clear(){memset(ch[0],0,sizeof(ch[0]));sz=1;}
    int idx(char x)
    {
        if(x=='R')return 0;
        return 1;
    }
    void insert(char *s,int id)
    {
        int u=0;
        int n=strlen(s);
        for(int i=0;i<n;i++)
        {
            int c=idx(s[i]);
            if(!ch[u][c])
            {
                memset(ch[sz],0,sizeof(ch[sz]));
                val[sz]=0;
                ch[u][c]=sz++;
            }
            u=ch[u][c];
        }
        val[u]|=(1<<id);
    }
    void getfail()
    {
        int u=0;
        queue<int> q;
        fail[0]=0;
        for(int c=0;c<SIGMA_SIZE;c++)
        {
            u=ch[0][c];
            if(u){fail[u]=0;q.push(u);}
        }
        while(!q.empty())
        {
            int r=q.front();q.pop();
            val[r]|=val[fail[r]];
            for(int c=0;c<SIGMA_SIZE;c++)
            {
                u=ch[r][c];
                if(!u){ch[r][c]=ch[fail[r]][c];continue;}
                q.push(u);
                int v=fail[r];
                while(v&&!ch[v][c])v=fail[v];
                fail[u]=ch[v][c];
            }
        }
    }
    void solve()
    {
        for(int x=0;x<=N;x++)
            for(int y=0;y<=M;y++)
                for(int i=0;i<sz;i++)
                    for(int j=0;j<4;j++)dp[x][y][i][j]=0;
        dp[0][0][0][0]=1;
        for(int x=0;x<=N;x++)
        {
            for(int y=0;y<=M;y++)
            {
                for(int i=0;i<sz;i++)
                {
                    for(int j=0;j<4;j++)
                    {
                        if(dp[x][y][i][j]==0)continue;
                        if(x<N)
                        {
                            int v=ch[i][0];
                            dp[x+1][y][v][j|val[v]]+=dp[x][y][i][j];
                            if(dp[x+1][y][v][j|val[v]]>=MOD)
                                dp[x+1][y][v][j|val[v]]-=MOD;
                        }
                        if(y<M)
                        {
                            int v=ch[i][1];
                            dp[x][y+1][v][j|val[v]]+=dp[x][y][i][j];
                            if(dp[x][y+1][v][j|val[v]]>=MOD)
                                dp[x][y+1][v][j|val[v]]-=MOD;
                        }
                    }
                }
            }
        }
        int ans=0;
        for(int i=0;i<sz;i++)
        {
            ans+=dp[N][M][i][3];
            if(ans>=MOD)ans-=MOD;
        }
        printf("%d\n",ans);
    }
}ac;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&N,&M);
        ac.clear();
        for(int i=0;i<2;i++)
        {
            scanf("%s",s);
            ac.insert(s,i);
        }
        ac.getfail();
        ac.solve();
    }
    return 0;
}




版权声明:本文为博主原创文章,未经博主允许不得转载。

HDU 4758 Walk Through Squares && AC自动机+状压DP

因为写错了一个变量名,debug了半个小时,又犯这样的错误。以此为戒。。。 题意:给你n个R、m个D,用这些字母组成一个字符串,再给你两个用R、D组成的单词,问你有多少种字符串包含这两个单词,单词可以...

hdu4758Walk Through Squares【AC自动机+dp】

On the beaming day of 60th anniversary of NJUST, as a military college which was Second Artillery Ac...

hdu4758---Walk Through Squares(AC自动机+dp)

Problem DescriptionOn the beaming day of 60th anniversary of NJUST, as a military college which was ...

hdu 4758 Walk Through Squares(自动机+DP)

Walk Through Squares Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Ot...

HDU 4117 GRE Words (AC自动机 + 线段树优化DP) 2011年成都现场赛G题

题目大意: 就是现在给出n (n 大致思路: 首先不难想到建立n个串的AC自动机, 用dp[i]表示最终剩下的串以第i个串结尾的的方案中权值和的最大值 那么dp[i] = max(dp[j] +...

hdu4758(ac自动机,状态压缩dp)

Walk Through Squares Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Oth...

hdu4758(AC自动机+状态压缩dp)

链接:点击打开链接 题意:在一个矩阵内从左上角走到右下角,向右走得到一个R向下走得到一个D,问最后有几种走到右下角时得到的字符串包含题中给出的两个字符串 代码: #include #include ...

hdu 4758 Walk Through Squares

AC自动机+DP。想了很久都没想出来。。。据说是一道很模板的自动机dp。。。原来自动机还可以这么跑啊。。。我们先用两个字符串建自动机,然后就是建一个满足能够从左上角到右下角的新串,这样我们就可以直接从...

hdu4758 hdu2825 hdu4057 AC自动机与状态压缩dp的结合

最近做到好几道关于AC自动机与状态压缩dp的结合的题,这里总结一下。 题目一般会给出m个字符串,m不超过10,然后求长度为len并且包含特定给出的字符串集合的字符串个数。 以HDU 4758为例:...

HDU4758 AC自动机+DP (HDU4758与HDU2222)

竟然刚刚发现滚动数组可以提高DP 的效率(旁白:这是为什么呢。。。) 总之DP 的题目实现效率非常重要啊ORZ HDU4758 求一个含有固定数量的0和固定数量的1 的01串,使得其包含两个给定的...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:hdu 4758 - Walk Through Squares(AC自动机+DP)现场赛
举报原因:
原因补充:

(最多只允许输入30个字)