UVA - 11468 Substring

本文介绍了一个结合AC自动机和记忆化搜索算法的问题解决方法。该方法用于计算一组模式字符串作为随机生成文本子串的概率。文章详细展示了如何构建AC自动机,并通过动态规划计算得到“no”的概率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

AC自动机+记忆话搜索


Download as PDF

H

Substring

Input:Standard Input

Output:Standard Output

Given a set of pattern strings, and a text, you have to find, if any of the pattern is a substring of the text. If any of the pattern string can be found in text, then print “yes”, otherwise “no” (without quotes).

But, unfortunately, that’s not what is asked here.J

The problem described above, requires a input file generator. The generator generates a text of lengthL, by choosingLcharacters randomly. Probability of choosing each character is given as priori, and independent of choosing others.

Now, given a set of patterns, calculate the probability of a valid program generating “no”.

Input

First line contains an integerT, the number of test cases. Each case starts with an integerK, the number of pattern strings. NextKlines each contain a pattern string, followed by an integerN, number of valid characters.NextNlines each contain a character and the probability of selecting that character,pi. Next an integerL, the length of the string generated. The generated text can consist of only the valid characters, given above.

There will be a blank line after each test case.

Output

For each test case, output the number of test case, and the probability of getting a “no”.

Constraints

·T≤ 50

·K ≤ 20

·Length of each pattern string is between 1 and 20

·Each pattern string consists of only alphanumeric characters (‘a’ to ‘z’, ‘A’ to ‘Z’,’0’ to ‘9’)

·Valid characters are all alphanumeric characters

·∑pi= 1

·L ≤ 100

Sample InputOutput for Sample Input

2

1

a

2

a 0.5

b 0.5

2

2

ab

ab

2

a 0.2

b 0.8

2

Case #1: 0.250000

Case #2: 0.840000


Problem Setter: Manzurur Rahman Khan


每产生一个字母,相当与在AC自动机中任意走了一步。。。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>

using namespace std;

const int maxn=1700;

int idx(char c)
{
    if(c>='0'&&c<='9')
    {
        return c-'0';
    }
    else if(c>='a'&&c<='z')
    {
        return c-'a'+10;
    }
    else if(c>='A'&&c<='Z')
    {
        return c-'A'+10+26;
    }
}

int chd[maxn][65],match[maxn],f[maxn],sz;
bool vis[maxn][120];

void init()
{
    sz=1;
    memset(chd[0],0,sizeof(chd[0]));
    memset(match,0,sizeof(match));
    memset(f,0,sizeof(f));
}

void insert(char *p)
{
    int u=0;
    for(;*p;p++)
    {
        int t=idx(*p);
        if(!chd[u][t])
        {
            memset(chd[sz],0,sizeof(chd[sz]));
            chd[u][t]=sz++;
        }
        u=chd[u][t];
    }
    match[u]=1;
}

int getFail()
{
    queue<int> q;
    f[0]=0;
    for(int c=0;c<62;c++)
    {
        int u=chd[0][c];
        if(u)
        {
            f[u]=0;q.push(u);
        }
    }
    while(!q.empty())
    {
        int r=q.front();q.pop();
        for(int c=0;c<62;c++)
        {
            int u=chd[r][c];
            if(!u)
            {
                chd[r][c]=chd[f[r]][c]; continue;
            }
            q.push(u);
            int v=f[r];
            while(v&&!chd[v][c]) v=f[v];
            f[u]=chd[v][c];
            match[u]|=match[f[u]];
        }
    }
}

int K,N,L;
double prob[100],dp[maxn][120];

double getProb(int u,int l)
{
    if(l==0) return 1.;
    if(vis[u][l]) return dp[u][l];
    vis[u][l]=1;
    double a=0.;
    for(int i=0;i<62;i++)
    {
        if(!match[chd[u][i]])
            a+=prob[i]*getProb(chd[u][i],l-1);
    }
    return dp[u][l]=a;
}

int main()
{
    int t,cas=1;
    char word[30];
    scanf("%d",&t);
    while(t--)
    {
        init();
        scanf("%d",&K);
        for(int i=0;i<K;i++)
        {
            scanf("%s",word);
            insert(word);
        }
        getFail();
        memset(prob,0,sizeof(prob));
        scanf("%d",&N);
        for(int i=0;i<N;i++)
        {
            double p;
            scanf("%s%lf",word,&p);
            prob[idx(word[0])]=p;
        }
        memset(dp,0,sizeof(dp));
        memset(vis,0,sizeof(vis));
        scanf("%d",&L);
        printf("Case #%d: %lf\n",cas++,getProb(0,L));
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值