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

Posted cjlhy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;


/*
*/

 

以上是关于HDU - 6086 Rikka with String AC自动机 + dp的主要内容,如果未能解决你的问题,请参考以下文章

HDU 5634 Rikka with Phi

hdu 6090 Rikka with Graph

HDU 6095: Rikka with Competition

图论(生成树):HDU 5631Rikka with Graph

HDU 5631 Rikka with Graph

HDU6094 Rikka with K-Match