hdu 4758 Walk Through Squares

           AC自动机+DP。想了很久都没想出来。。。据说是一道很模板的自动机dp。。。哭原来自动机还可以这么跑啊。。。我们先用两个字符串建自动机,然后就是建一个满足能够从左上角到右下角的新串,这样我们直接从自动机中跑出一个满足题意的串就可以了,(貌似需要建新串的AC+DP都需要这么搞啊!)可以利用chd数组去递推得到状态的种数。这里我们用dp[ i ][ j ][ k ][ s ]表示当字符的位置为在矩阵中位置为(i, j)时,及向右走了 i 次,向下走了 j 次,时到达自动机上下标为k 的节点时状态为 s (1表示有串1,2表示有串2,3表示两个串都有)的种数。

 

#include <algorithm>

#include <iostream>

#include <sstream>

#include <cstdlib>

#include <climits>

#include <cstring>

#include <cstdio>

#include <string>

#include <vector>

#include <cctype>

#include <queue>

#include <cmath>

#include <set>

#include <map>

#define CLR(a, b) memset(a, b, sizeof(a))



using namespace std;

typedef long long LL;



const int MAX_NODE = 110 * 2;

const int MOD = 1000000007;

const int CHILD_NUM = 2;

const int N = 110;



class ACAutomaton

{

private:

    int chd[MAX_NODE][CHILD_NUM];

    int dp[2][N][MAX_NODE][4];

    int fail[MAX_NODE];

    int val[MAX_NODE];

    int Q[MAX_NODE];

    int ID[128];

    int sz;

public:

    void Initialize()

    {

        fail[0] = 0;

        ID['R'] = 0;

        ID['D'] = 1;

    }

    void Reset()

    {

        CLR(chd[0] , 0);

        CLR(val, 0);

        sz = 1;

    }

    void Insert(char *a, int hav)

    {

        int p = 0;

        for ( ; *a ; a ++)

        {

            int c = ID[*a];

            if (!chd[p][c])

            {

                memset(chd[sz] , 0 , sizeof(chd[sz]));

                chd[p][c] = sz ++;

            }

            p = chd[p][c];

        }

        val[p] |= hav;

    }

    void Construct()

    {

        int *s = Q , *e = Q;

        for (int i = 0 ; i < CHILD_NUM ; i ++)

        {

            if (chd[0][i])

            {

                fail[chd[0][i]] = 0;

                *e ++ = chd[0][i];

            }

        }

        while (s != e)

        {

            int u = *s++;

            for (int i = 0 ; i < CHILD_NUM ; i ++)

            {

                int &v = chd[u][i];

                if (v)

                {

                    *e ++ = v;

                    fail[v] = chd[fail[u]][i];

                    val[v] |= val[fail[v]];

                }

                else

                {

                    v = chd[fail[u]][i];

                }

            }

        }

    }

    int Work(int n, int m)

    {

        //最好手动初始化dp数组,不然如果没有用滚动数组的话会超时。

        for(int j = 0; j <= m; j ++)

                for(int k = 0; k < sz; k ++)

                    for(int s = 0; s < 4; s ++)

                        dp[0][j][k][s] = 0;

        dp[0][0][0][0] = 1;

        for(int i = 0; i <= n; i ++)

        {

            for(int j = 0; j <= m; j ++)

                for(int k = 0; k < sz; k ++)

                    for(int s = 0; s < 4; s ++)

                        dp[(i + 1) & 1][j][k][s] = 0;

            for(int j = 0; j <= m; j ++)

                for(int k = 0; k < sz; k ++)

                    for(int s = 0; s < 4; s ++)

                    {

                        if(i < n)

                        {

                            int next = chd[k][0];

                            int tmp = s | val[next];

                            dp[(i + 1) & 1][j][next][tmp] += dp[i & 1][j][k][s];

                            dp[(i + 1) & 1][j][next][tmp] %= MOD;

                        }

                        if(j < m)

                        {

                            int next = chd[k][1];

                            int tmp = s | val[next];

                            dp[i & 1][j + 1][next][tmp] += dp[i & 1][j][k][s];

                            dp[i & 1][j + 1][next][tmp] %= MOD;

                        }

                    }

        }

        int ret = 0;

        for(int i = 0; i < sz;i ++)

        {

            ret = (ret + dp[n & 1][m][i][3]) % MOD;

        }

        return ret;

    }

} AC;



int main()

{

    //freopen("input.txt", "r", stdin);

    AC.Initialize();

    int n, t, m;

    scanf("%d", &t);

    while (t --)

    {

        AC.Reset();

        scanf("%d%d", &n, &m);

        for (int i = 1 ; i <= 2 ; i ++)

        {

            char temp[N];

            scanf("%s", temp);

            AC.Insert(temp, i);

        }

        AC.Construct();

        printf("%d\n", AC.Work(n, m));

    }

    return 0;

}


 

 

你可能感兴趣的:(HDU)