HDU 3058 Generator [AC自动机+期望DP]

  给出M个短串,这些短串由前N个大写字母组成。然后随机的按字符生成字符串,每次生成1~N个字符的概率是相等的,当生成串包含任意一个指定短串时,就停止生成。问生成串的长度的期望是多少。

  首先建立Trie图,对每个可能作为短串结束的点都打上标记。用E(x)表示从这个点走到停止生成所需长度的期望。显然,对于打标记的点,E(x)=0。对于没打标记的点E(x)=∑(E(next[x][i])*1/N)+1(0<i<N),next[x][i]是它在trie图中接受字母i后走到的点。

  然后根据Trie图建立方程组,用高斯消元求解E(0)即可。

  高斯消元的精度着实很低,现在的代码能过G++,但C++还是WA。。。。估计还是什么地方精度有问题。。

  

  1 #include <string.h>
  2 #include <stdio.h>
  3 #include <math.h>
  4 #include <algorithm>
  5 #define MAXN 105
  6 const double eps=1e-12;
  7 int cas,n,m;
  8 char s[12];
  9 int next[MAXN][8],flag[MAXN],fail[MAXN],pos;
 10 int newnode(){
 11     memset(next[pos],0,sizeof next[pos]);
 12     flag[pos]=fail[pos]=0;
 13     return pos++;
 14 }
 15 void insert(char *s){
 16     int p=0;
 17     for(int i=0;s[i];i++){
 18         int &x=next[p][s[i]-'A'];
 19         p=x?x:x=newnode();
 20     }
 21     flag[p]=1;
 22 }
 23 int q[MAXN],front,rear;
 24 void makenext(){
 25     q[front=rear=0]=0,rear++;
 26     while(front<rear){
 27         int u=q[front++];
 28         for(int i=0;i<n;i++){
 29             int v=next[u][i];
 30             if(v==0)next[u][i]=next[fail[u]][i];
 31             else q[rear++]=v;
 32             if(v&&u){
 33                 fail[v]=next[fail[u]][i];
 34                 flag[v]|=flag[fail[v]];
 35             }
 36         }
 37     }
 38 }
 39 int id[MAXN],w,h;
 40 double mat[MAXN][MAXN],ans[MAXN];
 41 void makemat(){
 42     w=h=0;
 43     memset(id,0,sizeof id);
 44     memset(mat,0,sizeof mat);
 45     for(int i=0;i<pos;i++)
 46         if(flag[i]==0)id[i]=w++;
 47     for(int u=0;u<pos;u++){
 48         if(flag[u]==0){
 49             mat[h][id[u]]=-n;
 50             mat[h][w]=n;
 51             for(int i=0;i<n;i++){
 52                 int v=next[u][i];
 53                 if(flag[v]==1)continue;
 54                 mat[h][id[v]]+=1.0;
 55             }
 56             h++;
 57         }
 58     }
 59     w++;
 60 }
 61 double gauss(){
 62     makemat();
 63     int row=0,col=0;
 64     for(;row<h&&col<w;col++){
 65         int maxr=row;
 66         for(int i=row+1;i<h;i++)
 67             if(fabs(mat[i][col])>fabs(mat[maxr][col]))maxr=i;
 68         if(fabs(mat[maxr][col])<eps)continue;
 69         if(maxr!=row)for(int i=0;i<w;i++)std::swap(mat[maxr][i],mat[row][i]);
 70         for(int k1=row+1;k1<h;k1++){
 71             double div=mat[k1][col]/mat[row][col];
 72             for(int k2=col;k2<w;k2++){
 73                 mat[k1][k2]-=div*mat[row][k2];
 74             }
 75         }
 76         row++;
 77     }
 78     memset(ans,0,sizeof ans);
 79     for(int i=h-1;i>=0;i--){
 80         double tmp=0;
 81         for(int j=i+1;j<w-1;j++){
 82             tmp+=ans[j]*mat[i][j];
 83         }
 84         ans[i]=(mat[i][w-1]-tmp)/mat[i][i];
 85     }
 86     return -ans[0];
 87 }
 88 int main(){
 89     //freopen("test.in","r",stdin);
 90     scanf("%d",&cas);
 91     while(cas--){
 92         scanf("%d%d",&n,&m);
 93         pos=0;newnode();
 94         for(int i=1;i<=m;i++){
 95             scanf("%s",s);
 96             insert(s);
 97         }
 98         makenext();
 99         double res=gauss();
100         printf("%.2f\n",res);
101     }
102 }
原文地址:https://www.cnblogs.com/swm8023/p/2683829.html