uva 11468 Substring

本文详细解析了UVA11468 Substring问题,利用AC自动机与概率DP解决字符串匹配及概率计算难题,提供完整的代码实现及运行流程说明。

uva 11468 Substring

题意:给你 k 个模板串,然后给你一些字符的出现概率,然后给你一个长度 l ,问你这些字符组成的长度为 l 的字符串不包含任何一个模板串的概率。

思路:AC自动机+概论DP

上次记不得AC自动机怎么写了,今天又写了一波,结果又写GG了,太久没碰字符串了啊;

首先用K个模板构造好AC自动机。题目上说长L的新串的子串不包含任何一个K串,其实就是说在构造好的树中,从根往下走L步都不包含K个模板,遇到ed就停下

#include<bits/stdc++.h>
using namespace std;
const int ME = 1000;
int idc, siz = 63, tot, fail[ME], ch[ME][64];
char s[25];
bool ed[ME], vis[ME][105];

double dp[ME][105], p[100];
inline int go(char a){
    if(a<='9'&&a>='0')return a-'0';
    if(a<='z'&&a>='a')return a-'a'+11;
    return a-'A'+37;
}
inline int newnode(){
    ++tot;
    ed[tot] = fail[tot] = 0;
    memset(ch[tot], 0, sizeof(ch[tot]));
    return tot;
}
void insert(char *s){
    int now = 0, len = strlen(s);
    for(int i = 0; i < len; i++){
        int t = go(s[i]);
        if(!ch[now][t])ch[now][t] = newnode();
        now = ch[now][t];
    }
    ed[now] = 1;
}
queue <int> q;
void build(){
    for(int i = 0; i < siz; i++){
        if(ch[0][i])q.push(ch[0][i]);
    }
    fail[0] = -1;
    while(!q.empty()){
        int u = q.front();q.pop();
        for(int i = 0; i < siz; i++){
            if(ch[u][i])q.push(ch[u][i]), fail[ch[u][i]] = ch[fail[u]][i];
            else ch[u][i] = ch[fail[u]][i];
        }
        ed[u] |= ed[fail[u]];
    }
}
double dfs(int u, int l){
    if(!l)return 1.0;
    if(vis[u][l])return dp[u][l];
    vis[u][l] = 1;
    double tmp = 0;
    for(int i = 0; i < siz; i++)
        if(!ed[ch[u][i]]) tmp += p[i] * dfs(ch[u][i], l-1);
    return dp[u][l] = tmp;
}
void init(){
    memset(p, 0, sizeof(p));
    memset(vis, 0, sizeof(vis));
    tot = 0;
    memset(ch[0], 0, sizeof(ch[0]));
}

int main(){
    int T;
    scanf("%d", &T);
    while(T--){
        int K, n, l;
        scanf("%d", &K);
        init();
        for(int i = 1; i <= K; i++){
            scanf("%s", s);
            insert(s);
        }
        scanf("%d", &n);
        char c[2];double oi;
        for(int i = 1; i <= n; i++){
            scanf("%s%lf",c, &oi);
            p[go(c[0])] = oi;
        }
        scanf("%d", &l);
        build();
        double ans = dfs(0, l);
        printf("Case #%d: %.6lf\n",++idc, ans);
    }
}

 

转载于:https://www.cnblogs.com/EdSheeran/p/9831388.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值