WHU1572---Cyy and Fzz (AC自动机+dp)

Description
As Cyy and Fzz are both busy repairing the network, Sama feel a little boring because it’s he who select Teemo during that game. Of cause his Teemo will stay alive since he has used the summoner spell Flash to avoid being killed. Since there is no network available, he wants to do something else to pass the time. He writes some strings randomly on the paper to kill the boring time.
A few minutes later he realizes that what he writes on the paper is not truly random, in fact it reflects what he is concerned about. Then he comes up with a question, what is the expect number of interesting strings that will appear in the random string he writes? (The characters Sama writes are all lowercase Latin letters, in this problem we consider the probability that each character appears as the same, that is, 1/26)
Input
The first line is an integer T (T <= 13) indicates the case numbers.
Then followed by T test cases. The first line of each test case contains two integers n and L(n <= 8, L <= 14), the number of interesting strings and the length of the string that Sama writes, then followed by n lines, the interesting strings. We promise that the interesting string is not longer than 12. (Notice that there may exist two or more same strings among the n interesting strings.)
Output
For each test case output one line, the expect number of interesting strings that will appear in the string Sama writes (Accurate to 6 digits after the decimal point).
Sample Input
3
1 1
a
3 4
cyy
fzz
sama
8 14
fatezero
nisekoi
nogamenolife
monthlygirls
nozakikun
datealive
sakura
sora
Sample Output
0.038462
0.000230
0.000024
Hint

dp[i][j][sta] 表示长度为i,在节点j,包含串的状态为sta的概率,最后求出期望就行

/************************************************************************* > File Name: I.cpp > Author: ALex > Mail: [email protected] > Created Time: 2015年04月19日 星期日 16时09分56秒 ************************************************************************/

#include <functional>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <queue>
#include <stack>
#include <map>
#include <bitset>
#include <set>
#include <vector>

using namespace std;

const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const double eps = 1e-15;
typedef long long LL;
typedef pair <int, int> PLL;

const int MAX_NODE = 200;
const int CHILD_NUM = 26;

double dp[20][MAX_NODE][300];

struct AC_Automation
{
    int next[MAX_NODE][CHILD_NUM];
    int fail[MAX_NODE];
    int end[MAX_NODE];
    int root, L;

    int newnode()
    {
        for (int i = 0; i < CHILD_NUM; ++i)
        {
            next[L][i] = -1;
        }
        end[L++] = 0;
        return L - 1;
    }

    void init ()
    {
        L = 0;
        root = newnode();
    }

    void Build_Trie (char buf[], int id)
    {
        int now = root;
        int len = strlen (buf);
        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'];
        }
        end[now] |= (1 << id);
    }

    void Build_AC ()
    {
        queue <int> qu;
        fail[root] = root;
        for (int i = 0; i < CHILD_NUM; ++i)
        {
            if (next[root][i] == -1)
            {
                next[root][i] = root;
            }
            else
            {
                fail[next[root][i]] = root;
                qu.push (next[root][i]);
            }
        }
        while (!qu.empty())
        {
            int now = qu.front();
            qu.pop();
            end[now] |= end[fail[now]];
            for (int i = 0; i < CHILD_NUM; ++i)
            {
                if (next[now][i] == -1)
                {
                    next[now][i] = next[fail[now]][i];
                }
                else
                {
                    fail[next[now][i]] = next[fail[now]][i];
                    qu.push(next[now][i]);
                }
            }
        }
    }

    void solve(int n, int m)
    {
        memset(dp, 0, sizeof(dp));
        dp[0][0][0] = 1;
        for (int i = 0; i < m; ++i)
        {
            for (int j = 0; j < L; ++j)
            {
                for (int sta = 0; sta < (1 << n); ++sta)
                {
                    if (dp[i][j][sta])
                    {
                        for (int k = 0; k < CHILD_NUM; ++k)
                        {
                            int nxt = next[j][k];
                            dp[i + 1][nxt][end[nxt] | sta] += (1.0 / 26) * dp[i][j][sta];
                        }
                    }
                }
            }
        }
        double ans = 0;
        for (int i = 0; i < L; ++i)
        {
            for (int j = 0; j < (1 << n); ++j)
            {
                int cnt = 0;
                for (int k = 0; k < n; ++k)
                {
                    if (j & (1 << k))
                    {
                        ++cnt;
                    }
                }
                ans += cnt * dp[m][i][j];
            }
        }
        printf("%f\n", ans);
    }
}AC;

char str[50];

int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        int n, L;
        scanf("%d%d", &n, &L);
        AC.init();
        for (int i = 0; i < n; ++i)
        {
            scanf("%s", str);
            AC.Build_Trie(str, i);
        }
        AC.Build_AC();
        AC.solve(n, L);
    }
    return 0;
}

你可能感兴趣的:(dp,AC自动机)