zoukankan      html  css  js  c++  java
  • HDU 2825 Wireless Password【AC自动机+DP】

    给m个单词,由这m个单词组成的一个新单词(两个单词可以重叠包含)长度为n,且新单词中包含的基本单词数目不少于k个。问这样的新单词共有多少个?


    m很小,用二进制表示新单词中包含基本单词的情况。

    用m个单词建立AC自动机,可以求出所有单词之间相互包含的情况,AC自动机的后缀特性(每个结点的失配边指向新结点,新节点到trie树根的字符串是当前节点字符串的后缀)。


    动态规划:

    f(i, j, k):长度为i的单词,在trie树中第j个结点处,包含基本单词的情况为k(二进制),的总方案数。


    转移方程:

    在当前字符串后边再加上一个字母

    f(i+1, u, k|val[u]) += f(i, j, k)

    u是j结点的子结点(或者是失配边指向的结点),k|val[u]表示加上一个新字母后包含基本单词的情况。


    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    using namespace std;
    struct AC_Automata {
        #define N 102
        #define M 26
        int ch[N][M], val[N], last[N], f[N], sz;
        void clear() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); }
        int idx(char c) { return c-'a'; }
    
        void insert(char s[], int v) {
            int u = 0;
            for (int i=0; s[i]; i++) {
                int c = idx(s[i]);
                if (!ch[u][c]) {
                    memset(ch[sz], 0, sizeof(ch[sz]));
                    val[sz] = 0;
                    ch[u][c] = sz++;
                }
                u = ch[u][c];
            }
            val[u] = 1<<v;
        }
        void build() {
            queue<int> q;
            f[0] = 0;
            for (int c=0; c<M; c++) {
                int u = ch[0][c];
                if (u) { f[u] = last[u] = 0; q.push(u); }
            }
            while (!q.empty()) {
                int r = q.front(); q.pop();
                for (int c=0; c<M; c++) {
                    int u = ch[r][c];
                    if (!u) {
                        ch[r][c] = ch[f[r]][c];
                        val[r] = val[r] | val[f[r]];  //从根到当前结点组成的字符串后缀包含基本单词的情况(传递)
                        continue;
                    }
                    q.push(u);
                    f[u] = ch[f[r]][c];
                    last[u] = val[f[u]] ? f[u] : last[f[u]];
                }
            }
        }
    } ac;
    int c[1030]; ///记录每个状态含有几个串
    int f[27][102][1025];
    
    void init() {
        memset(c, 0, sizeof(c));
        for (int i=0; i<1024; i++) {
            for (int j=0; j<10; j++)
                if ((1<<j) & i) c[i]++;
        }
    }
    void solve(int n, int m, int p) {
        #define Mod 20090717
        int u;
        for (int i=0; i<=n; i++)
            for (int j=0; j<ac.sz; j++)
                for (int k=0; k<(1<<m); k++)
                    f[i][j][k] = 0;
        f[0][0][0] = 1;
    
        for (int i=0; i<n; i++)
            for (int j=0; j<ac.sz; j++) {
                for (int k=0; k<(1<<m); k++) {
                    if (f[i][j][k] == 0) continue;
                    for (int jj=0; jj<M; jj++) {
                        u = ac.ch[j][jj];
                        f[i+1][u][ac.val[u]|k] = (f[i+1][u][ac.val[u]|k] + f[i][j][k]) % Mod;
                    }
                }
            }
    
        int ans = 0;
        for (int i=0; i<ac.sz; i++)
            for (int j=0; j<(1<<m); j++)
                if (c[j] >= p) ans = (ans + f[n][i][j]) % Mod;
        printf("%d
    ", ans);
    }
    int main() {
        int n, m, k;
        char s[12];
        init();
    
        while (scanf("%d%d%d", &n, &m, &k) == 3) {
            if (n == 0 && m == 0 && k == 0) break;
            ac.clear();
    
            for (int i=0; i<m; i++) {
                scanf(" %s", s);
                ac.insert(s, i);
            }
            ac.build();
    
            solve(n, m, k);
    
        }
        return 0;
    }
    


  • 相关阅读:
    adb检测不到夜神模拟器
    夜神模拟器相关设置
    dos窗口下查看系统环境变量设置,输出dos命令结果到文件
    JavaScript DOM操作案例列表的高亮显示
    JavaScript DOM操作案例美女相册
    JavaScript DOM操作案例阻止超链接跳转
    JavaScript DOM操作案例点击按钮修改ul背景颜色
    Git 状态 untracked 和 not staged的区别
    GitPython模块简介
    解决error: failed to push some refs to 'xxxx'
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3253566.html
Copyright © 2011-2022 走看看