UVA 11468 Substring

  题目大意:给出n种字符和其出现的概率,给出一些模板串,求随机生成长度为L的串中不含任意模板串作为子串的概率。模板串个数≤20,串长≤20,L≤100。    

  这么多个模板串肯定是AC自动机。

  不出现任意一个模板串,即走不到AC自动机上val有值(标为单词结尾)的点。

  随机生成长度为L的字符串,即在AC自动机上随机走L步。

  处理方法是记忆化搜索。设g(x,step)表示当前在AC自动机的点x上、还需要走step步,走不到结尾点的概率。那么答案就是g(0,L)。

  那么转移根据全概率公式(感性证明)就是

  

  能转移当且仅当ch[x][i]不是一个串的结尾。

  边界条件是g(x,0)=1。

#include    <iostream>
#include    <cstdio>
#include    <cstdlib>
#include    <algorithm>
#include    <vector>
#include    <cstring>
#include    <queue>
#include    <complex>
#include    <stack>
#define LL long long int
#define dob double
#define FILE "11468"
using namespace std;

const int N = 1010;
const int M = 71;
int n,L,K,tot,ch[N][M],id[N],val[N],fail[N];
double P[N][N],pro[N];
bool vis[N][N];
char S[N][N],g[M];

inline int gi(){
  int x=0,res=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
  while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  return x*res;
}

inline void insert(char *s,int rt=0){
  for(int i=0,j=strlen(s);i<j;++i){
    int x=id[s[i]];
    if(!ch[rt][x]){
      ch[rt][x]=++tot;val[tot]=0;
      memset(ch[tot],0,sizeof(ch[tot]));
    }
    rt=ch[rt][x];
  }
  val[rt]=1;
}

inline void getfail(){
  queue<int>Q;fail[0]=val[0]=0;
  for(int i=1;i<=n;++i){
    int y=ch[0][i];
    if(y)fail[y]=0,Q.push(y);
  }
  while(!Q.empty()){
    int x=Q.front();Q.pop();
    for(int i=1;i<=n;++i){
      int y=ch[x][i];
      if(!y){
        ch[x][i]=ch[fail[x]][i];
        continue;
      }
      Q.push(y);int z=fail[x];
      while(z && ch[z][i]==0)z=fail[z];
      fail[y]=ch[z][i];val[y]|=val[fail[y]];
    }
  }
}

inline double getprob(int x,int step){
  if(!step)return 1.0;
  if(vis[x][step])return P[x][step];
  vis[x][step]=1;double ans=0.0;
  for(int i=1;i<=n;++i)
    if(!val[ch[x][i]])
      ans+=pro[i]*getprob(ch[x][i],step-1);
  return P[x][step]=ans;
}

inline void solve(){
  K=gi();tot=0;
  memset(ch[0],0,sizeof(ch[0]));
  memset(vis,0,sizeof(vis));
  for(int i=1;i<=K;++i)scanf("%s",S[i]);
  n=gi();memset(id,0,sizeof(id));
  for(int i=1;i<=n;++i){
    scanf("%s%lf",g,&pro[i]);
    id[g[0]]=i;
  }
  for(int i=1;i<=K;++i)insert(S[i]);
  getfail();L=gi();
  double ans=getprob(0,L);
  printf("%.6lf\n",ans);
}

int main()
{
  freopen(FILE".in","r",stdin);
  freopen(FILE".out","w",stdout);
  int Case=gi();
  for(int t=1;t<=Case;++t){
    printf("Case #%d: ",t);
    solve();
  }
  fclose(stdin);fclose(stdout);
  return 0;
}
Substring

 

posted @ 2017-10-19 21:14  Fenghr  阅读(226)  评论(0编辑  收藏  举报