zoukankan      html  css  js  c++  java
  • bzoj 2553 [BeiJing2011]禁忌——AC自动机+概率DP+矩阵

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2553

    看了题解才会……

    首先,给定一个串,最好的划分方式是按禁忌串出现的右端点排序,遇到能填的就填上。在 AC 自动机上就是一旦能走到一个禁忌串的终止节点,就 ans++ 并走到根去。

    考虑怎么把 ans++ 也体现在矩阵乘法里。而且还要期望……

    只要在矩阵里填上概率,最后就能算出期望了。体现 ans++ 的话,就是在 “从当前节点到根” 的同时给 “从当前节点到 tot ” 的概率也加上 ( frac{1}{alphabet} ) 即可。

    最后就看一下乘了 len 次之后从根走到 tot 点的值即可。

    听说要开 long double 。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define db long double
    using namespace std;
    const int N=80,K=30;
    int n,m,alp,tot=1,c[N][K],fl[N],q[N]; db p;
    char ch[N]; bool en[N];
    struct Mtr{
      db a[N][N];
      Mtr(){for(int i=1;i<=tot;i++)for(int j=1;j<=tot;j++)a[i][j]=0;};
      Mtr operator* (const Mtr &b)const
      {
        Mtr c;
        for(int i=1;i<=tot;i++)
          for(int k=1;k<=tot;k++)
        for(int j=1;j<=tot;j++)
          c.a[i][j]+=a[i][k]*b.a[k][j];
        return c;
      }
    }t,ans;
    void get_fl()
    {
      int he=0,tl=0;
      for(int j=0;j<alp;j++)
        if(c[1][j])q[++tl]=c[1][j],fl[c[1][j]]=1;
        else c[1][j]=1;
      while(he<tl)
        {
          int k=q[++he]; if(en[fl[k]])en[k]=1;
          for(int j=0;j<alp;j++)
        {
          if(c[k][j])
            {
              int cr=fl[k];
              while(cr&&!c[cr][j])cr=fl[cr];
              if(c[cr][j])fl[c[k][j]]=c[cr][j];
              else fl[c[k][j]]=1;
              q[++tl]=c[k][j];
            }
          else
            {
              int cr=fl[k];
              while(cr&&!c[cr][j])cr=fl[cr];
              if(c[cr][j])c[k][j]=c[cr][j];
              else c[k][j]=1;
            }
        }
        }
    }
    int main()
    {
      scanf("%d%d%d",&n,&m,&alp); p=1.0/alp;
      for(int i=1;i<=n;i++)
        {
          scanf("%s",ch+1);
          int d=strlen(ch+1), cr=1;
          for(int j=1;j<=d;j++)
        {
          int w=ch[j]-'a';
          if(!c[cr][w])c[cr][w]=++tot;
          cr=c[cr][w];
        }
          en[cr]=1;
        }
      get_fl(); tot++; t.a[tot][tot]=1;
      for(int i=1;i<tot;i++)
        for(int j=0;j<alp;j++)
          {
        if(en[c[i][j]]){ t.a[i][1]+=p; t.a[i][tot]+=p;}
        else t.a[i][c[i][j]]+=p;
          }
      ans=t; m--;
      while(m)
        {
          if(m&1)ans=ans*t; t=t*t;m>>=1;
        }
      printf("%.10Lf
    ",ans.a[1][tot]);
      return 0;
    }
  • 相关阅读:
    HDU
    CodeForces
    CodeForces
    TensorFlow下利用MNIST训练模型并识别自己手写的数字
    李宏毅机器学习笔记2:Gradient Descent(附带详细的原理推导过程)
    李宏毅机器学习笔记1:Regression、Error
    tensorflow相关API的学习
    解决winscp中普通用户无法上传、删除、移动文件
    2019最新最全HUSTOJ本地及云端服务器搭建(基于腾讯云服务器)
    解决Ubuntu无法进行SSH连接的问题(以及如何使用SSH)
  • 原文地址:https://www.cnblogs.com/Narh/p/10687543.html
Copyright © 2011-2022 走看看