LA3490 Generator(AC自动机或者kmp + dp +高斯消元)

来源:互联网 发布:c语言非空基本数据类型 编辑:程序博客网 时间:2024/06/03 16:09

【题意】

            就是现在一个字符串生成器每次随机扔出前n(n <= 26)个大写英语字母的一个。将产生的字符连接起来成为其生成的字符串,如果它产生的字符串中有连续的一段出现了给定的禁止串,则生成停止。求停止时已经生成的字符串长度的期望

【解题方法】

           去网上看了一下题解,发现是dp+高斯小圆。于是开始自己推dp方程,觉得没问题了,开始写。那个转移那个地方,惯性写了个AC自动机!然后插入的时候才发现他妈只有一个字符串啊,要毛的AC自动机啊。kmp直接就搞下来了啊。TAT

          来说一下这个题的解题方法吧!

 首先建立AC自动机得到状态转移图  * 用E[i]表示在转移图中的点i处到达目标状态需要的期望步数, 则E[0]即为解(root == 0)  * 由于只有一个串记其结尾位置为AC自动机中的点L - 1长度为L的话  * 显然E[L - 1] = 0 (L为AC自动机上的总点数)  * 对于0 <= i < L - 1有转移方程E[i] = ∑(E[next[i][j]] + 1) / n , (0 <= j < n)  * L - 1 <= 12可以使用高斯消元求解复杂度O(L^3) AC自动机复杂度O(L) *Trick 不能用double 的guass,因为会损失精度,直接WA 

【AC 代码】我是真他妈蠢啊。

////Simpsons’ Hidden Talents//Created by just_sort 2016/9/28 18:41//Copyright (c) 2016 just_sort.All Rights Reserved//#include <set>#include <map>#include <queue>#include <stack>#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;char s[20];int n;struct Acauotmata{    int root,L,ch[15][26],fail[15],cnt[15];//Acautomata    int var,equ;    LL a[15][15],x[15];//Guass equ个方程,var个变量    int newnode(){        memset(ch[L],-1,sizeof(ch[L]));        cnt[L] = 0;        return L++;    }    void init(){        L = equ = var = 0;        root = newnode();    }    int id(char c){        return c-'A';    }    void insert(char *s){        int u = root;        int len = strlen(s);        for(int i = 0; i < len; i++){            if(ch[u][id(s[i])] == -1){                ch[u][id(s[i])] = newnode();            }            u = ch[u][id(s[i])];        }        cnt[u] = 1;    }    void build(){        fail[root] = root;        queue<int>q;        q.push(root);        while(!q.empty()){            int now = q.front();            q.pop();            for(int i = 0; i < n; i++){                if(ch[now][i] == -1){                    ch[now][i] = now == root?root:ch[fail[now]][i];                }                else{                    fail[ch[now][i]] = now ==root?root:ch[fail[now]][i];                    q.push(ch[now][i]);                }            }        }    }    void getxishu()    {        memset(a,0,sizeof(a));        var = L;        for(int i = 0; i < L-1; i++){            a[equ][i] += n;            for(int j = 0; j < n; j++){                a[equ][ch[i][j]] -= 1;            }            x[equ++] = n;        }        a[equ][L-1] = 1;        x[equ++] = 0;    }    void debug(){        for(int i = 0; i < L; i++){            for(int j = 0; j < L-1; j++){                printf("%lld ",a[i][j]);            }            printf("%lld\n",x[i]);        }        printf("\n");    }    LL Guass()    {        for(int i = 0; i < equ; i++){            int r = i;            while(r < equ && !a[r][i]) r++;            if(r != i){                for(int j = 0; j < var; j++){                    swap(a[r][j],a[i][j]);                }                swap(x[r],x[i]);            }            for(int k = i+1; k < equ; k++){                if(a[k][i]){                    int tmp = a[k][i];                    for(int j = i; j < var; j++) a[k][j] = a[k][j]*a[i][i] - tmp*a[i][j];                    x[k] = x[k]*a[i][i] - tmp*x[i];                }            }        }        for(int i = equ-1; i >= 0; i--){            for(int j = i+1; j < var; j++) x[i] -= x[j]*a[i][j];            x[i] /= a[i][i];        }        return x[0];    }}ac;int main(){    int T;    scanf("%d",&T);    for(int ks = 1; ks <= T; ks++){        scanf("%d",&n);        ac.init();        scanf("%s",s);        ac.insert(s);        ac.build();        ac.getxishu();        //ac.debug();        printf("Case %d:\n",ks);        printf("%lld\n",ac.Guass());        if(ks != T){            printf("\n");        }    }    return 0;}



0 0
原创粉丝点击