UVA 11468(Substring-AC自动机上dp)[Template:AC自动机]

Substring

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 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, the number 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

Sample
input

2

1

a

2

a
0.5

b
0.5

2

2

ab

ab

2

a
0.2

b
0.8

2

Output
for Sample Input

Case
#1: 0.250000

Case
#2: 0.840000

本题利用了AC自动机

首先,把模式串p推入AC自动机,然后dp[i][j]表示匹配到i点没成功,还剩j个字符未匹配的概率,dp

注意AC自动机上的dp(我之前忘了getFail()了,,,考挂自己弱)

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
#include<queue>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXT (50+10)
#define MAXL (100+10)
#define MAXN (20+10)
#define MAXLen (20+10)
#define MAXNode (400+10)
#define Sigma_size (62)
typedef long long ll;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}

int n,L;
char s[MAXLen];
double prob[Sigma_size],dp[MAXNode][MAXL];
bool b[MAXNode][MAXL]; 

class Aho_Corasick_Automata
{
public:
	int ch[MAXNode][Sigma_size];
	int v[MAXNode],siz;
	// AC自动机
	int f[MAXNode],last[MAXNode];
	Aho_Corasick_Automata(int _siz=0):siz(_siz){MEM(ch) MEM(v) MEM(f) MEM(last)}
	void mem(int _siz=0){siz=_siz; MEM(ch) MEM(v) MEM(f) MEM(last)	}
	int idx(char c){return 'a'<=c&&c<='z'?c-'a':'A'<=c&&c<='Z'?c-'A'+26:c-'0'+52;}
	void insert(char *s,int val=0)
	{
		int u=0,n=strlen(s);
		Rep(i,n)
		{
			int c=idx(s[i]);
			if (!ch[u][c])
			{
				++siz;
				MEM(ch[siz]);
				ch[u][c]=siz;
			}
			u=ch[u][c];
		}
		v[u]=val;
	}
	void getFail()
	{
		queue<int> q;
		Rep(c,Sigma_size)
		{
			int u=ch[0][c];
			if (u) q.push(u),last[u]=0;
		}
		while (!q.empty())
		{
			int r=q.front();q.pop();  //r--c-->u
			Rep(c,Sigma_size)
			{
				int u=ch[r][c];
				if (!u) {ch[r][c]=ch[f[r]][c]; continue;}
				q.push(u);
				f[u]=ch[f[r]][c];
				last[u]=v[f[u]]?f[u]:last[f[u]];
			}
		}
	}
	void print(int j) //打印全串中所有以j为末尾的str
	{
		if (j)
		{
			printf("%d %d\n",j,v[j]);
			print(last[j]);
		}
	}
	void find(char *s)
	{
		int u=0,n=strlen(s);
		Rep(i,n)
		{
			int c=idx(s[i]);
			u=ch[u][c];
			if (v[u]) print(u);
			else if (last[u]) print(u);
		}
	}

	double dfs(int u,int l)
	{
		if (!l) return 1;
		if (b[u][l]) return dp[u][l];
		double ans=0.0;
		Rep(c,Sigma_size)
		if (prob[c])
		{
			if (v[ch[u][c]]||last[ch[u][c]]) continue;
			ans+=prob[c]*dfs(ch[u][c],l-1);
		}	

		b[u][l]=1;
		return dp[u][l]=ans;
	}

}T;

int main()
{
//	freopen("uva11468.in","r",stdin);
//	freopen(".out","w",stdout);
	int kcase;
	scanf("%d",&kcase);
	For(tt,kcase)
	{
		T.mem();
		MEM(dp) MEM(prob) MEM(b)

		scanf("%d",&n);
		For(i,n)
		{
			scanf("%s",s);
			T.insert(s,1);
		}
		T.getFail(); 

		scanf("%d\n",&n);
		For(i,n)
		{
			char c;
			scanf("%c",&c);
			scanf("%lf\n",&prob[T.idx(c)]);
		}

		scanf("%d",&L);

		printf("Case #%d: %.6lf\n",tt,T.dfs(0,L));
	}

	return 0;
}
时间: 2024-10-07 09:18:28

UVA 11468(Substring-AC自动机上dp)[Template:AC自动机]的相关文章

POJ2778 DNA Sequence AC自动机上dp

网址:https://vjudge.net/problem/POJ-2778 题意: 给出字符集${A,C,G,T}$和一些字符串(长度不超过$10$,且数量不超过$10$个),求长度为$n(n \leq 2e9)$的字符串中不包括上面这些字符串的字符串的数量. 题解: 我们可以先考虑一种方式:设$dp(i,j)$是用了$i$个字符拼出符合题意的长度为$j$的字符串的数量,在本题中$dp(i,j)=\sum _{j' \subseteq j} dp(i-1,j')$,显然时间复杂度是指数级的,不

uva 11468 - Substring(AC自动机+概率)

题目链接:uva 11468 - Substring 题目大意:给出一些字符和各自字符对应的选择概率,随机选择L次后得到一个长度为L的字符串,要求该字符串不包含任意一个子串的概率. 解题思路:构造AC自动机之后,每随机生成一个字母,等于是在AC自动机上走一步,所有子串的结束位置的节点标记为禁止通行,然后问题转换成记忆搜索处理. #include <cstdio> #include <cstring> #include <queue> #include <algor

UVA 11468 - Substring(AC自动机)

UVA 11468 - Substring 题目链接 题意:给定一些模式串,然后给出一些字母出现的概率,每次随机出现一个字母,要求出这些字母出现L个组成的字符串不包含(即不是它的连续字串)已有模式串的概率 思路:AC自动机,先构造出AC自动机,构造的时候利用next数组的特性,记录下每个位置是否有经过一个单词结点,如果有这个结点就是不能走的结点,那么问题就变成了只能在能走的结点上走L步的概率,注意这里空边也要处理成可以走(走到它的next,因为不匹配的话就一直找到next能匹配的位置),然后进行

URAL 1158 AC自动机上的简单DP+大数

题目大意 在一种语言中的字母表中有N(N<=50)个字母,每个单词都由M(M<=50)个字母构成,因此,一共可以形成N^M个单词.但是有P(P<=10)个串是被禁止的,也就是说,任何单词的子串都不能包含这P个串中的任意一个.问按照上述规则,能产生的合法串一共有多少个? 例如:N=3 M=3 P=3 字母表中的三个字符是QWE 被禁止的串为”QQ”,”WEE”,”Q”,则合法的串一共有7个. 这题目相当于通过步数对AC自动机上每一个点的状态进行DP dp[i][j]表示到达i这个点,走了j

poj--1625Censored!+AC自动机上的dp+大数

题目链接:点击进入 其实看起来是完全可以用矩阵做的,但是因为用到了大数的,导致内存开不下,所以用dp写了.其实dp的过程依旧就是在我们用禁止出现单词构建的trie上走m步的过程.我们定义dp[i][j]表示走过i步以后到达节点j的方案数,则状态转移应该是dp[i][j]=sum(dp[i-1][k]),其中k表示可以走到j的节点,并且不能是病毒节点.但是其实这样代码就不是那么好写了,其实我们可以用节点j主动的去更新它的子节点k,这样转移方程就成了dp[i][next[j][k]]+=dp[i-1

bzoj 1030: [JSOI2007]文本生成器 (ac自动机上的dp)

1030: [JSOI2007]文本生成器 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 2635  Solved: 1090 [Submit][Status][Discuss] Description JSOI交给队员ZYX一个任务,编制一个称之为"文本生成器"的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章-- 也就是说,生成的文章中

hdu 3992 AC自动机上的高斯消元求期望

Crazy Typewriter Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 391    Accepted Submission(s): 109 Problem Description There was a crazy typewriter before. When the writer is not very sober, it

AC自动机+全概率+记忆化DP UVA 11468 Substring

题目传送门 题意:训练之南P217 分析:没有模板串也就是在自动机上走L步,不走到val[u] == v的节点的概率 PS:边读边insert WA了,有毒啊! #include <bits/stdc++.h> using namespace std; const int K = 20 + 5; const int L = 100 + 5; const int NODE = K * K; const int SIZE = 66; int idx[256], n; struct AC { int

POJ 3691 AC自动机上的dp

题目大意: 给定一些不合理的DNA序列,再给一段较长的dna序列,问最少修改几次可以使序列中不存在任何不合理序列,不能找到修改方法输出-1 这里你修改某一个点的DNA可能会影响后面,我们不能单纯的找匹配数,因为你找到了你也不一定有方法改变它 这里用DP来解决 判断到第i位dna , 之前dp值保存了前面dna所能到达的所有状态: dp[i][j] 也就是用了前i个dna所到达的状态至少需要修改的值 从所有状态出发,经过AGCT4种情况到达下一个状态,只要下一个状态不为非法状态即可 过程中只要判断