HDU - 6086 Rikka with String AC自动机 + dp

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; s[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\n", ans);
    }
    return 0;
}

/*
*/

猜你喜欢

转载自www.cnblogs.com/CJLHY/p/11107848.html