[BZOJ2553] [BeiJing 2011] Taboo-AC Automata

Posted by UKlee on Sun, 14 Jul 2019 00:25:46 +0200

[BZOJ2553] [BeiJing 2011] Taboos

Description

People on Magic Land always mention the legend that their ancestor John helped Koishi and his sister Satori eventually draw on the eastern island. Then Koishi regained the ability to read the mind...

Now, in an era when John had become a legend, people who visited the island again found Koishi in trouble.
This time she met Flandre Scarlet, who had the ability to use taboo magic without being hurt.
To illustrate what taboo magic is and its harm, the following concepts are introduced:

1. Each non-empty string on the alphabet set A corresponds to a magic.
A is a collection of pre-alphabet lowercase letters.

2. There is a set T, each of which contains a string T on N alphabet sets A is called a Taboo string.

3. A magic, or equivalently, its corresponding string s, which contains taboos, causes harm to the user in the following ways:

 To divide s into several segments, considering the number of segments in the taboo string, different segmentation may have different numbers, the maximum value of which is the damage.

Because of her mind-reading ability, Koishi always randomly uses Flandre Scarlet's magic, which, to be sure, corresponds to all len strings on the alphabet set A.

However, some of the magic used by Flandre Scarlet is taboo, because of its own characteristics, she can use taboo magic without being harmed, and Koishi is different. Poor Koishi faces the threat of taboo damage every time he uses his opponent's magic.

What you need to calculate now is if Koishi's probability of using each other's magic is equal, what is the expected value of the taboo damage to each random use of magic?

Input

The first line contains three positive integers N, len, alphabet.
Next, N lines, each containing a string Ti, representing a tabu string.

Output

A non-negative real number represents the expected value of the taboo injury suffered.

Sample Input

2 4 2
aa
abb

Sample Output

0.75

[Example 1 Interpretation]

There are altogether 2 ^ 4 = 16 different kinds of magic.

It should be noted that the taboo injury of "aabb" is 1 instead of 2.

HINT

In 100% of the data, N is less than 5, len is less than 109, and 1 is less than alphabet is less than 26.

In all data, there are no less than 40% of the data: N = 1.

The data ensures that the length of each string Ti does not exceed 15 and is not empty.

The data ensures that each Ti contains only the first alphabet lowercase letters.

Data guarantees that there are no identical elements in set T, i.e., Ti_T j for any different I and j.

[Scoring Method]

For each group of data, 0 points are scored if the correct output (TLE, MLE, RTE, output format error, etc.) is not obtained.

Otherwise: Assume your output is YourAns and the standard output is StdAns:

Note MaxEPS = max (1.0, StdAns) *10-6

If | YourAns - StdAns | < MaxEPS, you get 10 points, otherwise you get 0 points.

That is, your answer needs to ensure that the relative error or absolute error does not exceed 10-6.

Hair Welfare La Hair Welfare La ~~o(((> = o)
This is our face of two protagonists Fulan and love~

Welfare is over. Back to the point:

String matching naturally uses AC automata~
The main idea is to find the expected maximum damage value of all strings len in length.
Expectations are obviously done with DP.~
So the probability of moving from I node to j node is expressed by f[i][j].
The answer, then, is the probability that all taboo strings will be reached.~

Implementation details:
bfs process DP.
A new node v (which does not exist on the automaton) is used to represent the end of the tabu string. If a tabu string ends on the automaton, the corresponding probability is added to the root node and v to represent the return to the root node and the statistical answer.
Finally, multiply len times by itself and use matrix to optimize power quickly.~

/**************************************************************
    Problem: 2553
    User:
    Language: C++
    Result: Accepted
    Time:56 ms
    Memory:1932 kb
****************************************************************/

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>

using namespace std;

const int N=100;

inline int read()
{
    int x=0;
    char ch=getchar();
    while(ch<'0' || '9'<ch)ch=getchar();
    while('0'<=ch && ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return x;
}

int n,alpha,len;
bool vis[N];

struct Matrix
{
    long double a[N][N];

    inline void init()
    {
        for(int i=0;i<N;i++)
            for(int j=0;j<N;j++)
                a[i][j]=0.0;
    }

    friend Matrix operator *(Matrix koishi,Matrix satori)
    {
        Matrix tmp;
        tmp.init();
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
                for(int k=0;k<=n;k++)
                    tmp.a[i][j]+=koishi.a[i][k]*satori.a[k][j];
        return tmp;
    }
}f,ans;

struct AC_Automaton
{
    int next[N][26],fail[N];
    int pool,l,r,q[N];
    bool end[N];

    AC_Automaton()
    {
        pool=0;
        memset(next,0,sizeof(next));
    }

    void add(char *s)
    {
        int len=strlen(s);
        int now=0;
        for(int i=0;i<len;i++)
        {
            if(!next[now][s[i]-'a'])
                next[now][s[i]-'a']=++pool;
            now=next[now][s[i]-'a'];
        }
        end[now]=1;
    }

    void getfail()
    {
        q[r=1]=0;l=0;
        fail[0]=-1;

        while(l!=r)
        {
            int u=q[++l];
            for(int i=0;i<alpha;i++)
            {
                if(next[u][i])
                {
                    q[++r]=next[u][i];
                    fail[next[u][i]]= u==0?0:next[fail[u]][i];
                }
                else
                    next[u][i]= u==0?0:next[fail[u]][i];
            }
            end[u]|=end[fail[u]];
        }
    }

    void build()
    {
        q[r=1]=0;l=0;
        vis[0]=1;
        long double base=1.0/(double)alpha;

        int u;
        while(l!=r)
        {
            u=q[++l];
            for(int i=0;i<alpha;i++)
            {
                if(!vis[next[u][i]])
                {
                    vis[next[u][i]]=1;
                    q[++r]=next[u][i];
                }

                if(end[next[u][i]])
                {
                    f.a[u][n]+=base;
                    f.a[u][0]+=base;
                }
                else
                    f.a[u][next[u][i]]+=base;
            }
        }
    }
}koishi;

int main()
{
    n=read();len=read();
    alpha=read();

    char s[N];
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s);
        koishi.add(s);
    }

    n=koishi.pool+1;
    koishi.getfail();
    koishi.build();

    for(int i=0;i<=n;i++)ans.a[i][i]=1;
    f.a[n][n]=1;

    while(len)
    {
        if(len&1)
            ans=f*ans;
        f=f*f;
        len>>=1;
    }

    printf("%.7f\n",(double)ans.a[0][n]);

    return 0;
}

Topics: less