UVA - 11468 Substring【AC自动机+记忆化搜索】

Time limit 10000 ms

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, thats not what is asked here.
The problem described above, requires a input file generator. The generator generates a text of length L, by choosing L characters 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 integer T, the number of test cases. Each case starts with an integer K, thenumber of pattern strings. Next K lines each contain a pattern string, followed by an integer N, number of valid characters. Next N lines each contain a character and the probability of selecting that character, pi . Next an integer L, 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


题目大意

(摘自lrj蓝书)给出一些字符和各自对应的选择概率,随机L次后得到一个长度为L的随机字符串S。给出K个模板串,计算S不包含任何一个串的概率(即任何一个模板串都不是S的子串)


题目分析

模板串很多文本串只有一个很容易对应到AC自动机
构造AC自动机后,题意可简化为
从AC自动机根节点开始走 L L L步,不走到任何单词结点的概率

d p [ u ] [ k ] dp[u][k] dp[u][k]表示当前走到结点 u u u还剩下 k k k,不走到单词结点的概率
边界 d p [ u ] [ 0 ] = 1 dp[u][0]=1 dp[u][0]=1,直接记搜即可


#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long lt;
typedef double dd;

int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}

const int maxn=5010;
int T,cs,n,m,L;
int ch[maxn][70],cnt;
int rem[maxn],fail[maxn];
int pos[maxn],vis[maxn][110];
dd pi[maxn],dp[maxn][110];
char pt[maxn];
queue<int> q;

void init()
{
	cnt=0;
	memset(ch,0,sizeof(ch));
	memset(rem,0,sizeof(rem));
	memset(dp,0,sizeof(dp));
	memset(vis,0,sizeof(vis));
}

int get(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'+36;
}

void ins(char* ss,int len)
{
    int u=0;
    for(int i=0;i<len;++i)
    {
        int x=get(ss[i]);
        if(!ch[u][x]) ch[u][x]=++cnt;
        u=ch[u][x];
    }
    rem[u]=1;
}

void ACM()
{
    for(int i=0;i<=65;++i)
    if(ch[0][i]) fail[ch[0][i]]=0,q.push(ch[0][i]);

    while(!q.empty())
    {
        int u=q.front(); q.pop();
        for(int i=0;i<=65;++i)
        {
            if(!ch[u][i]) ch[u][i]=ch[fail[u]][i];
            else{
                fail[ch[u][i]]=ch[fail[u]][i];
                rem[ch[u][i]]|=rem[fail[ch[u][i]]];
                q.push(ch[u][i]);
            }
        }
    }
}

dd DP(int u,int k)
{
	if(vis[u][k]) return dp[u][k];
	if(k==0) return dp[u][k]=1.0;
	dd res=0;
	for(int i=1;i<=n;++i)
	{
		if(rem[ch[u][pos[i]]]) continue;
		res+=DP(ch[u][pos[i]],k-1)*pi[i];
	}
	vis[u][k]=1;
	return dp[u][k]=res;
}

int main()
{
	T=read();
	while(T--)
	{
		init(); m=read();
		for(int i=1;i<=m;++i)
		{
			scanf("%s",&pt);
			ins(pt,strlen(pt));
		}
		n=read();
		for(int i=1;i<=n;++i)
		{
			scanf("%s",&pt);
			pos[i]=get(pt[0]);
			scanf("%lf",&pi[i]);
		}
		L=read();
		
		ACM();
		printf("Case #%d: %.6lf\n",++cs,DP(0,L));
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值