zoukankan      html  css  js  c++  java
  • 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
    ", AC.Work(n, m));
        }
        return 0;
    }
    


  • 相关阅读:
    OAuth2在微服务架构中的应用
    使用SpringSecurity体验OAuth2 (入门2)
    SpringSecurity的配置分析
    SpringSecurity在Springboot下使用的初步体验
    Spring框架中的org.springframework.context.annotation.Import注解类
    使用SpringSecurity体验OAUTH2之一 (入门1)
    5. SpringBoot —— Actuator简介
    无题
    C# 委托的本质
    json 字符串 反序列化
  • 原文地址:https://www.cnblogs.com/riskyer/p/3358049.html
Copyright © 2011-2022 走看看