• BZOJ2553 Beijing2011禁忌(AC自动机+动态规划+矩阵快速幂+概率期望)


      考虑对一个串如何分割能取得最大值。那么这是一个经典的线段覆盖问题,显然每次取右端点尽量靠前的串。于是可以把串放在AC自动机上跑,找到一个合法串后就记录并跳到根。

      然后考虑dp。设f[i][j]表示前i位走到AC自动机上j节点的概率,枚举下个字符即可转移。同时记录此时期望伤害,找到合法串就统计入答案。

      并且注意到每次转移是相同的。矩阵快速幂优化即可。

      以及非常卡精度,需要全程long double。cout的保留小数位数误差是相当大的,必须用printf。并且转移到某个字符的概率即1/alphabet需要强制转换成long double,否则也会丢失精度。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define N 80
    #define double long double
    int n,m,S,trie[N][26],fail[N],val[N],q[N],cnt=0;
    char c[20];
    struct matrix
    {
        int n;double a[N][N];
        matrix operator *(const matrix&b) const
        {
            matrix c;c.n=n;memset(c.a,0,sizeof(c.a));
            for (int i=0;i<n;i++)
                for (int j=0;j<N;j++)
                    for (int k=0;k<N;k++)
                    c.a[i][j]+=a[i][k]*b.a[k][j];
            return c;
        }
    }f,a;
    void ins(char *a)
    {
        int n=strlen(a+1),t=0;
        for (int i=1;i<=n;i++)
        {
            if (!trie[t][a[i]-'a']) trie[t][a[i]-'a']=++cnt;
            t=trie[t][a[i]-'a'];
        }
        val[t]=1;
    }
    void build()
    {
        int head=0,tail=0;for (int i=0;i<S;i++) if (trie[0][i]) q[++tail]=trie[0][i];
        do
        {
            int x=q[++head];
            for (int i=0;i<S;i++)
            if (trie[x][i]) q[++tail]=trie[x][i],fail[trie[x][i]]=trie[fail[x]][i],val[trie[x][i]]|=val[fail[trie[x][i]]];
            else trie[x][i]=trie[fail[x]][i];
        }while (head<tail);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj2553.in","r",stdin);
        freopen("bzoj2553.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),m=read(),S=read();
        for (int i=1;i<=n;i++) scanf("%s",c+1),ins(c);
        build();
        a.n=cnt+2;
        for (int i=0;i<=cnt;i++)
            for (int j=0;j<S;j++)
            if (val[trie[i][j]]) a.a[i][0]+=(double)1/S,a.a[i][cnt+1]+=(double)1/S;
            else a.a[i][trie[i][j]]+=(double)1/S;
        a.a[cnt+1][cnt+1]=1;
        f.n=1;f.a[0][0]=1;
        for (;m;a=a*a,m>>=1) if (m&1) f=f*a;
        printf("%.8Lf",f.a[0][cnt+1]);
        return 0;
    }
  • 相关阅读:
    执行sudo命令时command not found的解决办法
    CentOS7编译安装libc++和libc++abi
    CentOS 7 编译安装clang+llvm
    如何使用 Issue 管理软件项目?
    西门子 S7-300 PLC 从入门到精通的100个经典问题
    PLC_SIM 出现I/O访问错误-技术论坛-工业支持中心-西门子中国
    C# Lambda表达式
    C# Task中的Func, Action, Async与Await的使用
    C#委托的介绍(delegate、Action、Func、predicate)
    委托 你怎么看?
  • 原文地址:https://www.cnblogs.com/Gloid/p/9581650.html
Copyright © 2020-2023  润新知