UVA - 11468:Substring

随机生成一个字符可以看成在AC自动机里面向前走一个节点,那么ans就是0向前走L步并且不经过单词节点,

由概率知识可得,f[p][L]=∑f[nxt[p][i]][L-1]*g[i] 其中p表示位于p节点,还要走L步,边界是f[p][0]=1.0,可以用记忆化搜索

非常巧妙的做法

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
#define MAXN 25*25+10
using namespace std;
struct AC{
    int nxt[MAXN][65];
    int f[MAXN];
    int match[MAXN];
    int m;
    char ch[65];
    double g[65];
    int cnt;
    int vis[MAXN][MAXN];
    double ans[MAXN][MAXN];
    void init(){
        memset(vis,0,sizeof(vis));
        memset(nxt,0,sizeof(nxt));
        memset(f,0,sizeof(f));
        memset(match,0,sizeof(match));
        cnt=0;
    }
    int dex(char c){
        if('a'<=c&&c<='z')return c-97;
        if('A'<=c&&c<='Z')return c-65+26;
        return c-48+52;
    }
    void insert(char s[]){
        int p=0;
        int len=strlen(s);
        for(int i=0;i<len;i++){
            int t=dex(s[i]);
            if(!nxt[p][t]){
                nxt[p][t]=(++cnt);
            }
            p=nxt[p][t];
        }
        match[p]=1;
    }
    double work(int p,int L){
        if(!L)return 1.0;
        if(vis[p][L])return ans[p][L];
        vis[p][L]=1;
        double &ret=ans[p][L];
        ret=0.0;
        for(int i=1;i<=m;i++){
            int t=dex(ch[i]);
            if(!match[nxt[p][t]]){
                ret+=g[i]*work(nxt[p][t],L-1);
            }    
        }
        return ret;
    }
    void getFail(){
        queue<int> q;
        for(int i=0;i<65;i++){
            if(nxt[0][i]){
                q.push(nxt[0][i]);
            }
        }
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=0;i<65;i++){
                int y=nxt[x][i];
                if(!y){nxt[x][i]=nxt[f[x]][i];continue;}
                f[y]=nxt[f[x]][i];
                match[y]|=match[f[y]];
                q.push(y);
            }
        }
    }
}A;
int n,m,L;
char s[105];
void solve(){
    A.init();
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        A.insert(s);
    }
    A.getFail();
    scanf("%d",&m);
    A.m=m;
    for(int i=1;i<=m;i++){
        double t;
        scanf("%s%lf",s,&t);
        A.ch[i]=s[0];
        A.g[i]=t;
    }    
    scanf("%d",&L);
    printf("%.6f\n",A.work(0,L));
}
int main()
{
//    freopen("data.in","r",stdin);
    int T;
    scanf("%d",&T);
    for(int i=1;i<=T;i++){ 
        printf("Case #%d: ",i);
        solve();
    }
    return 0;
}    

 

posted @ 2017-11-30 00:12  white_hat_hacker  阅读(126)  评论(0编辑  收藏  举报