zoukankan      html  css  js  c++  java
  • HDU

    HDU - 6086

    前缀和后缀分别建AC自动机, 考虑从两端往中间dp

    dp[ o ][ i ][ j ][ mask ] 表示放了前面和后面o个, 第一个自动机在 i 位置, 第二个自动机在 j 位置, 拥有的目标串的状态是mask的方案数。

    对于跨过两端的东西, 我们最后处理就好了。

    #include<bits/stdc++.h>
    #define LL long long
    #define LD long double
    #define ull unsigned long long
    #define fi first
    #define se second
    #define mk make_pair
    #define PLL pair<LL, LL>
    #define PLI pair<LL, int>
    #define PII pair<int, int>
    #define SZ(x) ((int)x.size())
    #define ALL(x) (x).begin(), (x).end()
    #define fio ios::sync_with_stdio(false); cin.tie(0);
    
    using namespace std;
    
    const int N = 121 + 7;
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int mod = 998244353;
    const double eps = 1e-8;
    const double PI = acos(-1);
    
    template<class T, class S> inline void add(T &a, S b) {a += b; if(a >= mod) a -= mod;}
    template<class T, class S> inline void sub(T &a, S b) {a -= b; if(a < 0) a += mod;}
    template<class T, class S> inline bool chkmax(T &a, S b) {return a < b ? a = b, true : false;}
    template<class T, class S> inline bool chkmin(T &a, S b) {return a > b ? a = b, true : false;}
    
    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
    
    const int M = 121;
    
    int T, n, L, mask[M][M];
    char t[M];
    string s[M];
    
    int dp[2][M][M][1 << 6];
    
    int (*f)[M][1 << 6] = dp[0];
    int (*g)[M][1 << 6] = dp[1];
    
    struct Ac { // 1. init before use  2. cheke character set
        int ch[M][2], f[M], tot, sz, subVal;
        int val[M];
        string str[M];
        inline int newNode() {
            tot++; f[tot] = val[tot] = 0; str[tot] = "";
            memset(ch[tot], 0, sizeof(ch[tot]));
            return tot;
        }
        void init(int _sz, int _subVal) {
            sz = _sz; subVal = _subVal;
            tot = -1; newNode();
        }
        inline int idx(int c) {return c - subVal;}
        void addStr(char* s, int who) {
            int u = 0;
            for(int i = 0; s[i]; i++) {
                int c = idx(s[i]);
                if(!ch[u][c]) {
                    ch[u][c] = newNode();
                    str[ch[u][c]] = str[u];
                    str[ch[u][c]].push_back(s[i]);
                }
                u = ch[u][c];
            }
            val[u] |= (1 << who);
        }
        void build() {
            queue<int> que;
            for(int c = 0; c < sz; c++) {
                int v = ch[0][c];
                if(!v) ch[0][c] = 0;
                else f[v] = 0, que.push(v);
            }
            while(!que.empty()) {
                int u = que.front(); que.pop();
                val[u] |= val[f[u]];
                for(int c = 0; c < sz; c++) {
                    int v = ch[u][c];
                    if(!v) ch[u][c] = ch[f[u]][c];
                    else f[v] = ch[f[u]][c], que.push(v);
                }
            }
        }
    } ac[2];
    
    int main() {
        scanf("%d", &T);
        while(T--) {
            ac[0].init(2, '0'); ac[1].init(2, '0');
            memset(mask, 0, sizeof(mask));
            scanf("%d%d", &n, &L);
            for(int i = 0; i < n; i++) {
                scanf("%s", t);
                s[i] = t;
                int m = strlen(t);
                ac[0].addStr(t, i);
                reverse(t, t + m);
                ac[1].addStr(t, i);
            }
            ac[0].build();
            ac[1].build();
            
            for(int i = 1; i <= ac[0].tot; i++) {
                for(int j = 1; j <= ac[1].tot; j++) {
                    string L = ac[0].str[i];
                    string R = ac[1].str[j];
                    reverse(ALL(R));
                    string now = L + R;
                    string tmp;
                    for(int p = 0; p < SZ(L); p++) {
                        for(int k = 0; k < n; k++) {
                            if(SZ(s[k]) == 1) continue;
                            tmp = now.substr(p, SZ(s[k]));
                            if(tmp == s[k]) mask[i][j] |= 1 << k;
                        }
                    }
                }
            }
            for(int i = 0; i <= ac[0].tot; i++) {
                for(int j = 0; j <= ac[1].tot; j++) {
                    for(int k = 0; k < (1 << n); k++) {
                        f[i][j][k] = 0;
                    }
                }
            }
            f[0][0][0] = 1;
            int ni, nj, nk;
            for(int o = 0; o < L; o++) {
                swap(f, g);
                for(int i = 0; i <= ac[0].tot; i++) {
                    for(int j = 0; j <= ac[1].tot; j++) {
                        for(int k = 0; k < (1 << n); k++) {
                            f[i][j][k] = 0;
                        }
                    }
                }
                for(int i = 0; i <= ac[0].tot; i++) {
                    for(int j = 0; j <= ac[1].tot; j++) {
                        for(int k = 0; k < (1 << n); k++) {
                            for(int c = 0; c < 2; c++) {
                                ni = ac[0].ch[i][c];
                                nj = ac[1].ch[j][c ^ 1];
                                nk = k | ac[0].val[ni] | ac[1].val[nj];
                                add(f[ni][nj][nk], g[i][j][k]);
                            }
                        }
                    }
                }
            }
            int ans = 0;
            for(int i = 0; i <= ac[0].tot; i++) {
                for(int j = 0; j <= ac[1].tot; j++) {
                    for(int k = 0; k < (1 << n); k++) {
                        if((mask[i][j] | k) == (1 << n) - 1) {
                            add(ans, f[i][j][k]);
                        }
                    }
                }
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
    
    /*
    */
  • 相关阅读:
    重视个人成长 远离心灵鸡汤——由一则“心灵鸡汤”想到的
    vim 学习
    针对不同包之间的action跳转,怎么配置?
    Bootstrap 栅格系统
    struts2的s:iterator 标签 详解
    struts2 <s:property/>标签的使用--输出时间格式转换
    Myeclipse中把java代码导成UML类图
    大学毕业后坚持学习有什么用
    【BZOJ2754】喵星球上的点名(AC自动机)
    Codeforces Round #466 (Div. 2)
  • 原文地址:https://www.cnblogs.com/CJLHY/p/11107848.html
Copyright © 2011-2022 走看看