bzoj-1030 文本生成器

141 篇文章 0 订阅
75 篇文章 0 订阅

题意:

给出一个n个单词的字典,单词长度<=100;

求长度为m的随机字符串中有多少个串至少包括一个单词;

n<=60,m<=100;


题解:

好久没有写AC自动机啦,如今还记得模板真是难得;

然而这似乎是Trie图?总之写出来不差几句话;

首先至少包括一个单词这个条件不太好弄;

那就转化一下,求不含单词的字符串个数;

然后就想办法处理这个;

定义状态,f[i][j]表示长度为i的字符串,最后几位的状态在Trie图上的结点编号;

那么转移显然了:

最开始f[0][1]是1;

从一个点到下一个点累加f;

如果目前结点代表的单词在字典中,f值为0;

有个小坑,就是可能有单词包括另一个单词,这时也要将大单词里的小单词标上标记;

就是在找fail的时候顺便标一下,具体可以看代码;

不过代码很丑= =,我反正是写不出来比较短的AC自动机。。。


代码:


#include<queue>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 128
#define M 6000
#define mod 10007
#define pr pair<int,int>
using namespace std;
int next[M][26],fail[M],root=1,tot=1;
int f[N][M];
char str[N];
bool is[M];
int pow(int x,int y)
{
	int ret=1;
	while(y)
	{
		if(y&1)
			ret=ret*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return ret;
}
void Insert(char *s)
{
	int p=root,index;
	while(*s!='\0')
	{
		index=*s-'A';
		if(!next[p][index])
			next[p][index]=++tot;
		p=next[p][index];
		s++;
	}
	is[p]=1;
}
void Build()
{
	queue<int>q;
	int x,p,i,temp;
	q.push(root);
	while(!q.empty())
	{
		x=q.front(),q.pop();
		for(i=0;i<26;i++)
		{
			p=next[x][i];
			temp=fail[x];
			while(temp)
			{
				if(next[temp][i])
				{
					if(p&&is[next[temp][i]])
						is[p]=1;
					(p?fail[p]:next[x][i])=next[temp][i];
					break;
				}
				temp=fail[temp];
			}
			if(!temp)	(p?fail[p]:next[x][i])=root;
			if(p)	q.push(p);
		}
	}
}
int main()
{
	int n,m,i,j,k,index,ans;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)
	{
		scanf("%s",str);
		Insert(str);
	}
	Build();
	f[0][1]=1;
	for(i=1;i<=m;i++)
	{
		for(j=1;j<=tot;j++)
		{
			for(k=0;k<26;k++)
			{
				index=next[j][k];
				if(is[index])	continue;
				f[i][index]=(f[i][index]+f[i-1][j])%mod;
			}
		}
	}
	for(i=1,ans=0;i<=tot;i++)
	{
		ans+=f[m][i];
		ans%=mod;
	}
	printf("%d\n",((pow(26,m)-ans)%mod+mod)%mod);
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值