• bzoj 1444 [Jsoi2009]有趣的游戏


    题目

    好像是(SDOI2017)某题的数据范围弱化版

    不过把这道题放到(SDOI2017)某题应该有(60)可以拿吧

    看到多串首先建(AC)自动机

    之后就可以视为把这个随机生成的字符串放到(AC)机上匹配,由于是随机生成,那么本质上就是在(AC)机上随机游走,走到有结束标记的点就停下来

    (dp[i])表示(i)点经过的期望次数,由于终点走到就停下了,所以终点的期望等价于概率

    非常显然我们可以列出这样的方程

    [dp_v=sum_{e(u,v)in G}dp_u imes w(u,v) ]

    (w(u,v))就是走这条边的概率

    但是(0)号节点是特殊的,因为这个节点是起点,期望次数应该加(1)

    也就是

    [dp_0=1+sum_{e(u,0)in G}dp_u imes w(u,v) ]

    之后就会发现这样的方程根本没有办法来推,因为(AC)机根本就不是一个拓扑结构

    所以我们把这些方程一个一个列出来,之后高斯消元来求出每一个(dp)的值

    复杂度(O(n^3m^3))

    代码

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #include<cmath>
    #define eps 1e-6
    #define re register
    #define maxn 205
    #define LL long long
    #define inf 999999999
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read()
    {
        char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
        while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    inline int check(double a) {if(std::fabs(a)<eps) return 1;return 0;}
    int n,m,len,cnt;
    char S[maxn];
    double P[maxn];
    double a[maxn][maxn],ans[maxn],dp[maxn];
    int son[maxn][26],fail[maxn],f[maxn];
    inline void ins(int o)
    {
        int now=0;
        for(re int i=1;i<=len;i++) 
        {
            if(!son[now][S[i]-'A']) son[now][S[i]-'A']=++cnt;
            now=son[now][S[i]-'A'];
        }
        f[now]=o;
    }
    inline void build()
    {
        std::queue<int> q;
        for(re int i=0;i<m;i++) if(son[0][i]) q.push(son[0][i]);
        while(!q.empty())
        {
            int k=q.front();q.pop();
            for(re int i=0;i<m;i++)
            if(son[k][i]) fail[son[k][i]]=son[fail[k]][i],q.push(son[k][i]);
                else son[k][i]=son[fail[k]][i];
        }
    }
    int main()
    {
        n=read(),len=read(),m=read();
        int p,q;
        for(re int i=0;i<m;i++)
            p=read(),q=read(),P[i]=double(p)/double(q);
        for(re int i=1;i<=n;i++) scanf("%s",S+1),ins(i);
        build();
        for(re int i=0;i<=cnt;i++)
        {
            if(f[i]) continue;
            for(re int j=0;j<m;j++)
                a[son[i][j]][i]+=P[j];
        }
        for(re int i=0;i<=cnt;i++)a[i][i]+=-1;
        a[0][cnt+1]=-1.0;
        for(re int i=0;i<=cnt;i++)
        {
            int now=i;
            for(re int j=i+1;j<=cnt;j++) if(std::fabs(a[j][i])>std::fabs(a[now][i])) now=j;
            std::swap(a[now],a[i]);
            for(re int j=cnt+1;j>=i;--j)
                a[i][j]/=a[i][i];
            for(re int j=i+1;j<=cnt;j++)
                for(re int k=cnt+1;k>=i;--k)
                    a[j][k]-=a[j][i]*a[i][k];
        }
        ans[cnt]=a[cnt][cnt+1];
        for(re int i=cnt-1;i>=0;i--)
        {
            ans[i]=a[i][cnt+1];
            for(re int j=i+1;j<=cnt;j++)
                ans[i]-=a[i][j]*ans[j];
        }
        for(re int i=0;i<=cnt;i++) dp[f[i]]=ans[i];
        for(re int i=1;i<=n;i++) 
        {
            if(check(dp[i])) puts("0.00");
            else printf("%.2lf
    ",dp[i]);
        }
        return 0;
    }
    
  • 相关阅读:
    C#内存释放(垃圾回收)
    C#内存释放(垃圾回收)
    C# winform窗口打开特效及窗口位置居中
    QString 字符串操作
    qt exe文件添加图标
    Qt 多语言转换
    加密算法比较
    C语言中最常用标准库函数
    fprintfAndFscanf简单操作
    vs使用fscanf和fprintf错误警告处理
  • 原文地址:https://www.cnblogs.com/asuldb/p/10328908.html
Copyright © 2020-2023  润新知