• BZOJ 1444 [JSOI2009]有趣的游戏 (Trie图/AC自动机+矩阵求逆)


    题目大意:给你$N$个长度相等且互不相同的模式串,现在有一个字符串生成器会不断生成字符,其中每个字符出现的概率是$p_{i}/q_{i}$,当生成器生成的字符串包含了某个模式串,则拥有该模式串的玩家胜利,然后游戏立即结束,求每个玩家获胜的概率 $N<=10$

    首先建出$Trie$图

    接着设$f[i]$表示匹配时停在i的概率,可得$f[ch{k}]+=f[i]*p_{k}/q_{k}$

    由于$N$很小,可以构建$dp$转移的邻接矩阵,由于生成器生成的串是无限长的,相当于把矩阵乘了无限次幂

    可以耍赖一点...把矩阵自乘很多次,反正是保留小数卡精度过

    正确的做法呢,就是利用等比数列求极限的方法,即$1/(1-p)$,1在这里是单位矩阵,$p$是邻接矩阵

    然后对$(1-p)$这个矩阵求逆即可

      1 #include <cmath>
      2 #include <queue>
      3 #include <vector>
      4 #include <cstdio>
      5 #include <cstring>
      6 #include <algorithm>
      7 #define NN 105
      8 #define maxn 100000
      9 #define ll long long
     10 #define dd double  
     11 #define uint unsigned int
     12 #define mod 1000000007
     13 #define idx(X) (X-'A')
     14 #define eps (1e-9)
     15 using namespace std;
     16 
     17 int n,m;
     18 int ed[NN];
     19 int p[20],q[20],L,num;
     20 
     21 struct M{
     22 dd f[NN][NN*2];
     23 friend M operator * (const M &a,const M &b){
     24     M ret;memset(&ret,0,sizeof(ret));
     25     for(int i=0;i<n;i++)
     26         for(int j=0;j<n;j++)
     27             for(int k=0;k<n;k++)
     28             ret.f[i][j]+=a.f[i][k]*b.f[k][j];
     29     return ret;
     30 }
     31 int Gauss()
     32 {
     33     int nn=n*2;
     34     for(int i=0;i<n;i++)
     35         f[i][i+n]=1;
     36     for(int i=0;i<n;i++)
     37     {
     38         for(int j=i;j<n;j++)
     39         if(fabs(f[j][i])>eps){
     40             for(int k=0;k<nn;k++)
     41                 swap(f[i][k],f[j][k]);
     42             break;
     43         }
     44         if(fabs(f[i][i])<eps) return 0;
     45         dd r=1.0/f[i][i];
     46         for(int j=i;j<nn;j++)
     47             f[i][j]*=r;
     48         for(int j=0;j<n;j++)
     49         if(j!=i){
     50             r=f[j][i];
     51             for(int k=i;k<nn;k++)
     52                 f[j][k]=f[j][k]-r*f[i][k];
     53         }
     54     }
     55     for(int i=0;i<n;i++)
     56         for(int j=0;j<n;j++)
     57             f[i][j]=f[i][j+n];
     58     return 1;
     59 }
     60 };
     61 
     62 struct AC{
     63 int ch[NN][26],fail[NN],tot,win[NN];
     64 void Build_Trie(char *str,int len,int id)
     65 {
     66     int x=0;
     67     for(int i=1;i<=len;i++){
     68         if(!ch[x][idx(str[i])])
     69             ch[x][idx(str[i])]=++tot;
     70         x=ch[x][idx(str[i])];
     71     }ed[id]=x;win[x]=1;
     72 }
     73 void Build_Fail()
     74 {
     75     queue<int>q;
     76     for(int i=0;i<m;i++)
     77         if(ch[0][i]) q.push(ch[0][i]);
     78     while(!q.empty())
     79     {
     80         int x=q.front();q.pop();
     81         for(int i=0;i<m;i++)
     82         {
     83             if(ch[x][i]){
     84                 fail[ch[x][i]]=ch[fail[x]][i];
     85                 q.push(ch[x][i]);
     86             }else{
     87                 ch[x][i]=ch[fail[x]][i];
     88             }
     89         }
     90     }
     91 }
     92 void Build_Martix(M &S)
     93 {
     94     for(int x=0;x<=tot;x++)
     95         if(!win[x]){
     96             for(int i=0;i<m;i++)
     97             S.f[ch[x][i]][x]+=1.0*p[i]/q[i];
     98         }
     99     for(int i=0;i<n;i++)
    100         for(int j=0;j<n;j++)
    101         if(i!=j) S.f[i][j]=0-S.f[i][j];
    102         else S.f[i][j]=1.0-S.f[i][j];
    103 }
    104 }ac;
    105 M ans,ni;
    106 
    107 int main()
    108 {
    109     //freopen("t1.in","r",stdin);
    110     scanf("%d%d%d",&num,&L,&m);
    111     for(int i=0;i<m;i++)
    112         scanf("%d%d",&p[i],&q[i]);
    113     char str[20];
    114     for(int i=1;i<=num;i++){
    115         scanf("%s",str+1);
    116         ac.Build_Trie(str,L,i);}
    117     ac.Build_Fail();
    118     n=ac.tot+1;
    119     ac.Build_Martix(ans);
    120     ans.Gauss();
    121     for(int i=1;i<=num;i++)
    122         printf("%.2lf
    ",ans.f[ed[i]][0]);
    123     return 0;
    124 }
  • 相关阅读:
    八. 输入输出(IO)操作2.面向字符的输入流
    八. 输入输出(IO)操作1.输入输出基本概念
    七. 多线程编程11.线程的挂起、恢复和终止
    七. 多线程编程10.线程死锁
    nginx 配置身份验证 http_auth_basic_module
    liunx mysql 备份
    8080 端口只允许内网访问配置
    nginx 配置白名单
    liunx tomcat 运行模式apr
    liunx contos 7.4 安装redis集群
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10015714.html
Copyright © 2020-2023  润新知