• Rikka with String HDU 6086


    题解: 要是这个东西没有反对称的概念,我们直接AC自动机+dp就可以很愉快的解决了,但是现在有了这个反对称的原则,在不考虑跨过中间的部分的话这个还是很容易的解决的,dp[i][j][k][state]代表到了第i个位置,在左串的j节点,右边的k节点此时的state,但是这样子的话我们发现了一个问题就是这个复杂度没有很好的利用反对称的这个性质。

    假如我们现在有一个00101的串,我们在左边匹配了01011也相当于匹配了这个串,所以这个复杂度就减少了。

    然后就是考虑跨过了中间位置的字符串,然后暴力枚举就行了。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int MAXNODE = 2500;
    const int SIGMA_SIZE = 2;
    const LL MOD = 998244353;
    
    struct ACauto {
        int next[MAXNODE][SIGMA_SIZE], fail[MAXNODE], end1[MAXNODE], end2[MAXNODE];
        int root,sz;
    
        int newnode() {
            for (int i = 0; i < SIGMA_SIZE; i++)
                next[sz][i] = -1;
            end1[sz] = 0;
            end2[sz++] = 0;
            return sz - 1;
        }
    
        void init() {
            sz = 0;
            root = newnode();
        }
    
        void insert1(char *buf, int id) {
            int len = strlen(buf);
            int now = root;
            for (int i = 0; i < len; i++) {
                if (next[now][buf[i] - '0'] == -1)
                    next[now][buf[i] - '0'] = newnode();
                now = next[now][buf[i] - '0'];
            }
            end1[now] |= (1 << id);
        }
    
        void insert2(char *buf, int id) {
            int len = strlen(buf);
            int now = root;
            for (int i = 0; i < len; i++) {
                if (next[now][buf[i] - '0'] == -1)
                    next[now][buf[i] - '0'] = newnode();
                now = next[now][buf[i] - '0'];
            }
            end2[now] |= (1 << id);
        }
    
        void build() {
            queue <int> Q;
            fail[root] = root;
            for (int i = 0; i < SIGMA_SIZE; i++) {
                if (next[root][i] == -1)
                    next[root][i] = root;
                else {
                    fail[next[root][i]] = root;
                    Q.push(next[root][i]);
                }
            }
            while (!Q.empty()) {
                int now = Q.front();
                Q.pop();
                end1[now] |= end1[fail[now]];
                end2[now] |= end2[fail[now]];
                for (int i = 0; i < SIGMA_SIZE; i++) {
                    if (next[now][i] == -1)
                        next[now][i] = next[fail[now]][i];
                    else {
                        fail[next[now][i]] = next[fail[now]][i];
                        Q.push(next[now][i]);
                    }
                }
            }
        }
    
    } ac;
    
    int n, L;
    char s[30], t[30], str[60];
    LL dp[13][2700][(1 << 6) + 10];
    
    int main() {
        //freopen("in.txt", "r", stdin);
        int T;
        scanf("%d", &T);
        while (T--) {
            scanf("%d%d", &n, &L);
            ac.init();
            for (int i = 0; i < n; i++) {
                scanf("%s", s);
                ac.insert1(s, i);
                //cout << i << endl;
               // cout << s << endl;
                int len = strlen(s);
                for (int j = 0; j < len; j++)
                    t[j] = s[len - 1 - j] == '0' ? '1' : '0';
                t[len] = '';
               ac.insert1(t, i);
                //printf("****
    ");
               // cout << t << endl;
                for (int j = 0; j < len - 1; j++) {
                    string s1 = "", s2 = "";
                    for (int k = j; k >= 0; k--) s1 += s[k];
                    for (int k = j + 1; k < len; k++) s2 += s[k];
                    //cout << " : " << s1 << "  " << s2 << endl;
                    bool flag = true;
                    for (int k = 0; k < (int)s1.length() && k < (int)s2.length(); k++) {
                        if (s1[k] == s2[k]) {
                            flag = false;
                            break;
                        }
                    }
                    if (!flag) continue;
                    reverse(s1.begin(), s1.end());
                    //cout << " -- " << s1 << endl;
                    for (int k = (j + 1) * 2; k < len; k++) {
                        s1 = (s[k] == '0' ? '1' : '0') + s1;
                    }
                    //cout << s1 << endl;
                    strcpy(str, s1.c_str());
                  //  printf("****
    ");
                    //printf("%s
    ",str);
                    ac.insert2(str, i);
                }
            }
            ac.build();
            memset(dp, 0, sizeof(dp));
            dp[0][0][0] = 1;
            for (int i = 0; i < L; i++) {
                for (int j = 0; j < ac.sz; j++) {
                    for (int S = 0; S < (1 << n); S++) {
                        if (dp[i%2][j][S] == 0) continue;
                        for (int k = 0; k < SIGMA_SIZE; k++) {
                            int ni = i + 1, nj = ac.next[j][k], nS = S | ac.end1[nj];
                            if (i == L - 1) nS |= ac.end2[nj];
                            dp[ni%2][nj][nS] = (dp[ni%2][nj][nS] + dp[i%2][j][S]) % MOD;
                        }
                        dp[i%2 ][j][S] = 0;
                    }
                }
            }
            LL ans = 0;
            for (int i = 0; i < ac.sz; i++) {
                ans = (ans + dp[L%2][i][(1 << n) - 1]) % MOD;
            }
            printf("%I64d
    ", ans);
        }
        return 0;
    }
    

      

  • 相关阅读:
    Linux/Android 系统怎么修改mac地址
    Vue.js和jQuery混合使用的一点注意事项
    wpf研究之道——datagrid控件及样式
    asp.net url重写
    如何解决一个问题
    Word 2007 封面、目录和正文页码单独设置
    .net 多线程
    我对asp.net运行机制的理解
    Firefox扩展安装
    谷歌chrome 插件(扩展)开发——谈谈安装
  • 原文地址:https://www.cnblogs.com/Heilce/p/7402664.html
Copyright © 2020-2023  润新知