zoukankan      html  css  js  c++  java
  • BZOJ 禁忌 AC自动机+概率DP+矩阵乘

    题目描述

           Magic Land上的人们总是提起那个传说:他们的祖先John在那个东方岛屿帮助Koishi与其姐姐Satori最终战平。而后,Koishi恢复了读心的能力……

          

    如今,在John已经成为传说的时代,再次造访那座岛屿的人们却发现Koishi遇到了新麻烦。

           这次她遇到了Flandre Scarlet——她拥有可以使用禁忌魔法而不会受到伤害的能力。

           为了说明什么是禁忌魔法及其伤害,引入以下概念:

    1.字母集A上的每个非空字符串对应了一个魔法。

    其中A是包含了前alphabet个小写字母的集合。

    2.有一个集合T,包含了N个字母集A上的字符串

    T中的每一串称为一个禁忌串(Taboo string

    3.一个魔法,或等价地,其对应的串s因为包含禁忌而对使用者造成的伤害按以下方式确定:

               s分割成若干段,考虑其中是禁忌串的段的数目,不同的分割可能会有不同的数目,其最大值就是这个伤害。

          

    由于拥有了读心的能力,Koishi总是随机地使用Flandre Scarlet的魔法,可以确定的是,她的魔法正好对应字母集A上所有长度为len的串

    但是,Flandre Scarlet所使用的一些魔法是带有禁忌的,由于其自身特性,她可以使用禁忌魔法而不受到伤害,而Koishi就不同了。可怜的Koishi每一次使用对方的魔法都面临着受到禁忌伤害的威胁。

     

           你现在需要计算的是如果Koishi使用对方的每一个魔法的概率是均等的,那么每一次随机使用魔法所受到的禁忌伤害的期望值是多少。

     

    输入

    第一行包含三个正整数Nlenalphabet

    接下来N行,每行包含一个串Ti,表示禁忌串。

    输出

    一个非负实数,表示所受到禁忌伤害的期望值。

     

    样例输入

    2 4 2
    
    aa
    
    abb
    


    样例输出

    0.75【样例1解释】一共有2^4 = 16种不同的魔法。需要注意的是“aabb”的禁忌伤害是1而不是2。

    因为不让在HZOJ 上交,那就补一篇博客吧Haha..


    首先用AC自动机的fail指针把Trie图建出来,方便转移,然后题目让求得实际上就是在A


    C自动机上走len步走到禁忌串的期望伤害.


    然而因为禁忌串比较多,无法统计方案,可以新加一个超级节点,把每一个禁忌串节点连向


    这个超级节点,权值为1/alphabet


    如果这个节点不是禁忌节点的话就枚举下一步的位置,权值为1/alphabet这样就构造出来了矩阵,快速幂一下就行了

    卡 double 差评

    #include <stdio.h>
    #include <cstring>
    #include <iostream>
    #include <iomanip>
    using namespace std;
    int n,len,alphabet,sz;
    const int MAXN = 150000;
    const int maxn = 26;
    char ch[MAXN];
     
     
    struct node{
        node *ch[maxn],*fail;
        bool is;
        node(){
            memset(ch,0,sizeof(ch));
            fail=NULL;
            is=0;
        }
    }*root,*q[MAXN],N[MAXN],*C=N;
     
    void insert(char *s){
        int len =strlen(s);
        node *now=root;
        for(int i=0;i<len;i++){
            if(now -> ch[s[i]-'a']==NULL)now -> ch[s[i]-'a'] = C++;
            now = now -> ch[s[i]-'a'];
        }
        now -> is = 1;
    }
     
    void build_ac(){
        int l=0,r=0;
        for(int i=0;i<26;i++)
            if(root->ch[i]){
                root->ch[i]->fail=root;
                q[++r]=root->ch[i];
            }
            else    root->ch[i]=root;
        while(l!=r){
            node *now = q[++l];
            for(int i=0;i<26;i++){
                if(now -> ch[i]){
                    q[++r]=now -> ch[i];
                    now -> ch[i] -> fail = now -> fail -> ch[i];
                    now -> ch[i] -> is |= now -> ch[i] -> fail -> is;
                }
                else now -> ch[i] = now -> fail -> ch[i];
            }
        }
    }
     
    struct matrix{
        long double m[85][85];
        matrix(){memset(m,0,sizeof(m));}
    };
     
    matrix operator * (matrix a,matrix b){
        matrix ans ;
        for(int i=0;i<=sz;i++)
            for(int j=0;j<=sz;j++)
                for(int k=0;k<=sz;k++)
                    ans.m[i][j]+=a.m[i][k]*b.m[k][j];
        return ans;
    }
     
    matrix operator ^ (matrix a,int n){
        matrix ans;
        for(int i=0;i<=sz;i++)ans.m[i][i]=1;
        for(;n;n>>=1,a=a*a)
            if(n&1)
                ans=ans*a;
        return ans;
    }
     
    int main(){
        root = C++;
        scanf("%d%d%d",&n,&len,&alphabet);
        for(int i=1;i<=n;i++){
            scanf("%s",ch);
            insert(ch);
        }
        build_ac();
        matrix ans;
        sz=C-N;
        long double tmp = 1.0/alphabet;
        for(int i=0;i<sz;i++)
            for(int j=0;j<alphabet;j++){
                if(N[i].ch[j]->is){
                    ans.m[i][0]+=tmp;
                    ans.m[i][sz]+=tmp;
                }
                else ans.m[i][N[i].ch[j]-N]+=tmp;
            }
        ans.m[sz][sz]=1;
        ans=ans^len;
        cout<<fixed<<setprecision(10)<<ans.m[0][sz];
    }







  • 相关阅读:
    「Codeforces 79D」Password
    「算法笔记」BSGS
    「Codeforces 468C」Hack it!
    「算法笔记」快速傅里叶变换(FFT)
    「算法笔记」2-SAT 问题
    「算法笔记」基础数论 2
    《算法笔记》二分—木棒切割问题&求凸多边形外接圆最大半径
    《算法笔记》区间贪心
    《算法笔记》PAT B1020 月饼、PAT B1023 组个最小数
    《算法笔记》n皇后问题
  • 原文地址:https://www.cnblogs.com/Cooook/p/7738479.html
Copyright © 2011-2022 走看看