• BZOJ 2553 禁忌


    首先我们要考虑给定一个串,如何将他划分,使得他有最多的禁忌串

    我们只需要按里面出现的禁忌串们的出现的右端点排序然后贪心就可以啦

    我们建出AC自动机,在AC自动机等价于走到一个包含禁忌串的节点就划分出一段

    那么不妨设f(i,j)表示走了i步当前在AC自动机的j节点上

    这样的DP方程跟BZOJ 1030是类似的

    但是由于i可能会很大,但是j是很小的,又因为每一步的转移都是一样的

    所以我们可以考虑矩阵乘法来优化DP

    可是当我们用AC自动机构建了转移矩阵之后,我们会发现我们没办法算答案

    我们只能算经过L步到达AC自动机某节点的概率

    那么我们不妨新建节点表示答案,在每次出现禁忌串的时候在新建节点上贡献相应的期望

    同时新建节点要将上次贡献得到的期望传递给下一次的转移

    所以矩阵中n->n存在转移

    值得一提的是:这个题目卡精度,我一开始写的double,结果WA了

    去网上看了看题解之后默默的改成了long double,然后A了

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    using namespace std;
     
    const int maxn=102;
    int n,L,k,cnt;
    bool vis[maxn];
    char s[maxn];
    int t[maxn][26];
    int fail[maxn];
    bool end[maxn];
    struct Matrix{
        long double a[maxn][maxn];
        Matrix(){memset(a,0,sizeof(a));}
    }A,ans;
    queue<int>Q;
     
    void insert(){
        scanf("%s",s+1);
        int len=strlen(s+1),now=1;
        for(int i=1;i<=len;++i){
            int id=s[i]-'a';
            if(!t[now][id])t[now][id]=++cnt;
            now=t[now][id];
        }end[now]=true;
    }
    void build_fail(){
        Q.push(1);fail[1]=0;
        while(!Q.empty()){
            int u=Q.front();Q.pop();
            end[u]|=end[fail[u]];
            for(int i=0;i<k;++i){
                int tmp=fail[u];
                while(tmp&&!t[tmp][i])tmp=fail[tmp];
                if(t[u][i]){
                    fail[t[u][i]]=tmp?t[tmp][i]:1;
                    Q.push(t[u][i]);
                }else t[u][i]=tmp?t[tmp][i]:1;
            }
        }A.a[n][n]=1;return;
    }
    void build_Matrix(){
        vis[1]=true;Q.push(1);
        long double tmp=1.0/k;
        while(!Q.empty()){
            int u=Q.front();Q.pop();
            for(int i=0;i<k;++i){
                if(!vis[t[u][i]]){
                    vis[t[u][i]]=true;
                    Q.push(t[u][i]);
                }
                if(end[t[u][i]]){
                    A.a[u][n]+=tmp;
                    A.a[u][1]+=tmp;
                }else A.a[u][t[u][i]]+=tmp;
            }
        }return;
    }
    Matrix operator *(const Matrix &A,const Matrix &B){
        Matrix C;
        for(int i=1;i<=n;++i){
            for(int j=1;j<=n;++j){
                for(int k=1;k<=n;++k){
                    C.a[i][j]=C.a[i][j]+A.a[i][k]*B.a[k][j];
                }
            }
        }return C;
    }
    Matrix pow_mod(int p){
        Matrix tmp;
        for(int i=1;i<=n;++i)tmp.a[i][i]=1;
        while(p){
            if(p&1)tmp=tmp*A;
            A=A*A;p>>=1;
        }return tmp;
    }
     
     
    int main(){
        scanf("%d%d%d",&n,&L,&k);cnt=1;
        for(int i=1;i<=n;++i)insert();
        n=cnt+1;
        build_fail();build_Matrix();
        ans=pow_mod(L);
        printf("%.7lf
    ",(double)(ans.a[1][n]));
        return 0;
    }
    

      

  • 相关阅读:
    怎么查看keras 或者 tensorflow 正在使用的GPU
    tf.layers.Dense与 tf.layers.dense的区别
    pytorch LSTM 简单形式
    JN_0025:在局域网中调试本地loaclhost项目
    JN_0024:浏览器打开弹窗
    JN_0023:谷歌浏览器启动项设置
    H5_0041:定义方法获取URL参数
    H5_0040:iframe 父子页面方法调用
    H5_0039:iframe 页面嵌套格式 安全选项sandbox
    Web_0008:win系统默认80端口被占用的处理方法
  • 原文地址:https://www.cnblogs.com/joyouth/p/5366399.html
Copyright © 2020-2023  润新知