UVA 11468 Substring

  題目大意:給出n種字符和其出現的機率,給出一些模板串,求隨機生成長度爲L的串中不含任意模板串做爲子串的機率。模板串個數≤20,串長≤20,L≤100。    ios

  這麼多個模板串確定是AC自動機。ide

  不出現任意一個模板串,即走不到AC自動機上val有值(標爲單詞結尾)的點。spa

  隨機生成長度爲L的字符串,即在AC自動機上隨機走L步。code

  處理方法是記憶化搜索。設g(x,step)表示當前在AC自動機的點x上、還須要走step步,走不到結尾點的機率。那麼答案就是g(0,L)。blog

  那麼轉移根據全機率公式(感性證實)就是字符串

  

  能轉移當且僅當ch[x][i]不是一個串的結尾。get

  邊界條件是g(x,0)=1。string

#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
相關文章
相關標籤/搜索