• WHU 1572 Cyy and Fzz (AC自动机 dp )


    题意:

         给出n个串,求任意长度为m的字符串包含串的个数的期望。(n<=8,m<=14,给定串的长度不超过12)。

    Solution:

         首先可以想到应该用概率DP,我们需要至少3维,dp[i][j][k]表示第i个数字为j,已经包含了k个串的概率.

         然后,问题是找到状态转移的方法

         由于是字符串相关,AC自动机应该是第一个想到的.

         然后注意到,对于k个串的k,直接求并不好维护,也没办法判断重复的 .由于只有8个串,自然就想到用更简单的方法,用状态压缩来存已经包含了哪些串.

         在建trie图的时候,要注意一个结点的状态应该是包含了它的fail节点的状态的.

         从u到v的转移

                     dp[i+1][u][sta[u]|sta[v]]+=dp[i][v][sta[v]]

    #include <iostream>
    #include <queue>
    #include <cstdio>
    #include <string>
    #include <cstring>
    using namespace std;
    const int SD = 26;
    const int MAXL = 1000;
    struct Tire {
        int next[MAXL][SD], fail[MAXL], eofs[MAXL];
        int Root, cnt;
        int newnode() {
            for (int i = 0; i < SD; i++)     next[cnt][i] = -1;
            eofs[cnt++] = 0;
            return cnt - 1;
        }
        void init() {
            cnt = 0;
            Root = newnode();
        }
        void Ins (char buf[], int k) {
            int len = strlen (buf);
            int now = Root;
            for (int i = 0; i < len; i++) {
                if (next[now][buf[i] - 'a'] == -1)
                    next[now][buf[i] - 'a'] = newnode();
                now = next[now][buf[i] - 'a'];
            }
            eofs[now] |= (1 << k);
        }
        void build() {
            queue<int> ql;
            fail[Root] = Root;
            for (int i = 0; i < SD; i++) {
                if (next[Root][i] == -1)
                    next[Root][i] = Root;
                else {
                    fail[next[Root][i]] = Root;
                    ql.push (next[Root][i]);
                }
            }
            while (!ql.empty() ) {
                int now = ql.front(); ql.pop();
                eofs[now] |= eofs[fail[now]];
                for (int i = 0; i < SD; i++)
                    if (next[now][i] == -1) {
                        next[now][i] = next[fail[now]][i];
                    }
                    else {
                        fail[next[now][i]] = next[fail[now]][i];
                        ql.push (next[now][i]);
                    }
            }
        }
    } AC;
    int Cs, n, m;
    char s[20];
    double dp[20][400][1 << 9], tmp = 1. / 26;
    int main() {
        scanf ("%d", &Cs);
        while (Cs--) {
            memset (dp, 0, sizeof dp);
            AC.init();
            scanf ("%d %d", &n, &m);
            for (int i = 0; i < n; i++) {
                scanf ("%s", s);
                AC.Ins (s, i);
            }
            AC.build();
    
            dp[0][0][0] = 1;
            for (int i = 0; i < m; i++)
                for (int u = 0; u < AC.cnt; u++)
                    for (int st = 0; st < (1 << n); st++)
                        if (dp[i][u][st] > 0)
                            for (int j = 0; j < SD; j++) {
                                int v = AC.next[u][j];
                                dp[i + 1][v][st | AC.eofs[v]] += dp[i][u][st] * tmp;
                            }
    
            double ans = 0;
            for (int i = 0; i < AC.cnt; i++)
                for (int st = 0; st < (1 << n); st++)
                    if (dp[m][i][st] > 0) {
                        int sum = 0;
                        for (int k = 0; k < n; k++)
                            if (st & (1 << k) ) sum++;
                        ans += dp[m][i][st] * sum;
                    }
            printf ("%.6f
    ", ans);
        }
    }
    View Code
  • 相关阅读:
    前端常用布局
    Vue, React, AngularJS, Angular2 我们对流行JavaScript框架们的选择
    使用vue-cli创建vue项目
    Null component Catalina
    初识MongoDB
    小米平板2 win10 MIUI互刷教程
    tomcat报错
    websocket
    前后端数据交互方法
    二叉排序树
  • 原文地址:https://www.cnblogs.com/keam37/p/4442799.html
Copyright © 2020-2023  润新知