「HNOI2004」「LuoguP2292」L语言(AC自动机
题目描述
标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的。现在你要处理的就是一段没有标点的文章。
一段文章T是由若干小写字母构成。一个单词W也是由若干小写字母构成。一个字典D是若干个单词的集合。我们称一段文章T在某个字典D下是可以被理解的,是指如果文章T可以被分成若干部分,且每一个部分都是字典D中的单词。
例如字典D中包括单词{‘is’, ‘name’, ‘what’, ‘your’},则文章‘whatisyourname’是在字典D下可以被理解的,因为它可以分成4个单词:‘what’, ‘is’, ‘your’, ‘name’,且每个单词都属于字典D,而文章‘whatisyouname’在字典D下不能被理解,但可以在字典D’=D+{‘you’}下被理解。这段文章的一个前缀‘whatis’,也可以在字典D下被理解,而且是在字典D下能够被理解的最长的前缀。
给定一个字典D,你的程序需要判断若干段文章在字典D下是否能够被理解。并给出其在字典D下能够被理解的最长前缀的位置。
输入输出格式
输入格式:
输入文件第一行是两个正整数n和m,表示字典D中有n个单词,且有m段文章需要被处理。之后的n行每行描述一个单词,再之后的m行每行描述一段文章。
其中1<=n, m<=20,每个单词长度不超过10,每段文章长度不超过1M。
输出格式:
对于输入的每一段文章,你需要输出这段文章在字典D可以被理解的最长前缀的位置。
输入输出样例
题解
为什么AC自动机没什么近乎模板的题写啊QAQ
在上古年代写过一个Trie+爆搜的代码↓
/*
qwerta
P2292 [HNOI2004]L语言
Accepted
100
代码 C++,1.01KB
提交时间 2018-05-19 16:28:10
耗时/内存
832ms, 6812KB
*/
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct emm{
int z[];
bool en;
}a[];
char s[];
int f[];
int t=;
void build()
{
int d=strlen(s)-;
int e=;
while(d>=)
{
if(a[e].z[s[d]-])e=a[e].z[s[d]-];
else e=a[e].z[s[d]-]=++t;
d--;
}
a[e].en=true;
return;
}
int ans=;
void search(int c)
{
int e=,d=c-;
while(d>=&&a[e].z[s[d]-])
{
//cout<<c<<" ";
e=a[e].z[s[d]-];
if(a[e].en)
{
if(f[d]||d==)
{f[c]=;ans=c;return;}
}
d--;
}
return;
}
int main()
{
//freopen("a.in","r",stdin);
int n,m;
cin>>n>>m;
for(int i=;i<=n;++i)
{
cin>>s;
build();
}
for(int i=;i<=m;++i)
{
ans=;
cin>>s;
int len=strlen(s);
memset(f,,sizeof(f));
f[]=;
for(int j=;j<=len;++j)
search(j);
cout<<ans<<endl;
}
return ;
}
感觉自己现在写不出这种上古绝学了QAQ(逃
用AC自动机把单词出现的位置跑出来,转换成区间
问题转换成选择不重合的区间从0开始覆盖,最远的覆盖到哪儿。
然后写一个BFS跑一下就行了。
BFS:首先把0push进队列,然后跑以0为左端点的区间,每次把右端点push进去。
加上判重之后可以$O(L)$。
居然比上古绝学慢了三百毫秒QAQ
/*
qwerta
P2292 [HNOI2004]L语言
Accepted
100
代码 C++,2.53KB
提交时间 2018-10-08 08:42:03
耗时/内存
1121ms, 28908KB
*/
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<cmath>
using namespace std;
#define R register
struct emm{
int fal;
int nxt[];
int tag,l;
}AC[];//Tree结构体
queue<int>q;
struct ahh{
int f,e;
}a[];//用来区间覆盖
int h[];
bool sf[];//判重
int main()
{
//freopen("a.in","r",stdin);
ios::sync_with_stdio(false);
cin.tie(false),cout.tie(false);//关闭同步流(卡常
int n,m;
cin>>n>>m;
int cnt=;
//build_Trie
for(R int i=;i<=n;++i)
{
string s;
cin>>s;
int len=s.length();
int now=;
for(R int j=;j<len;++j)
{
if(!AC[now].nxt[s[j]-'a'])
AC[now].nxt[s[j]-'a']=++cnt;
now=AC[now].nxt[s[j]-'a'];
}
AC[now].tag=i;
AC[now].l=len;//记录这个区间的长度
}
//get_fail
{
for(R int i=;i<;++i)
if(AC[].nxt[i])
{
AC[AC[].nxt[i]].fal=;
q.push(AC[].nxt[i]);
}
while(!q.empty())
{
int x=q.front();q.pop();
for(R int i=;i<;++i)
{
if(AC[x].nxt[i])
{
AC[AC[x].nxt[i]].fal=AC[AC[x].fal].nxt[i];
q.push(AC[x].nxt[i]);
}
else
AC[x].nxt[i]=AC[AC[x].fal].nxt[i];
}
}
}
//runAC
for(R int i=;i<=m;++i)
{
//cout<<"i="<<i<<endl;
memset(a,,sizeof(a));
memset(h,,sizeof(h));
int tot=;
string t;
cin>>t;
int lent=t.length();
int now=;
for(R int j=;j<lent;++j)
{
now=AC[now].nxt[t[j]-'a'];
for(R int k=now;k;k=AC[k].fal)
if(AC[k].tag)
{
//a[++tot].r=j;
//a[tot].l=j-AC[k].l+1;
int ll=j-AC[k].l+;//这个区间的左端点=右端点-长度+1
a[++tot].f=h[ll];//邻接链表加边
h[ll]=tot;
a[tot].e=j;
}
}
//cout<<"get"<<endl;
//bfs
memset(sf,,sizeof(sf));
int ans=-;
{
q.push();
while(!q.empty())
{
int x=q.front();q.pop();
//cout<<"x="<<x<<endl;
ans=max(ans,x-);
for(R int i=h[x];i;i=a[i].f)
if(!sf[a[i].e])//判重
{
sf[a[i].e]=;
q.push(a[i].e+);
//cout<<"push "<<a[i].e+1<<endl;
}
}
}
cout<<ans+<<endl;
}
return ;
}
「HNOI2004」「LuoguP2292」L语言(AC自动机的更多相关文章
- BZOJ 1212: [HNOI2004]L语言 [AC自动机 DP]
1212: [HNOI2004]L语言 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1367 Solved: 598[Submit][Status ...
- 【bzoj1212】[HNOI2004]L语言 AC自动机
题目描述 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成.一个字典D是若干个单词的 ...
- bzoj 1212: [HNOI2004]L语言 AC自动机+状压
为什么这道题网上所有题解写的都是N*Len的trie树的暴力啊,4E的复杂度... 为什么暴力还跑这么快啊TAT.. 有一个O(Len)的做法就是先把AC自动机建出来,因为每个字典串的长度很小,所以我 ...
- [HNOI2004] L语言 - AC自动机,dp
给定字典和没有标点的文章,求能够被识别的最长前缀. 显然不能贪心,设\(f[i]\)表示前\(i\)个字符构成的前缀能否被识别,然后在AC自动机上暴力转移即可. 具体来说,每走到一个新位置,就沿着fa ...
- 「模拟赛20180306」回忆树 memory LCA+KMP+AC自动机+树状数组
题目描述 回忆树是一棵树,树边上有小写字母. 一次回忆是这样的:你想起过往,触及心底--唔,不对,我们要说题目. 这题中我们认为回忆是这样的:给定 \(2\) 个点 \(u,v\) (\(u\) 可能 ...
- [bzoj1212][HNOI2004]L语言_AC自动机_动态规划
L语言 bzoj-1212 HNOI-2004 题目大意:给你一个n个单词的集合,然后给你m条字符串.问每条字符串可以被理解的最长前缀.被理解当且仅当存在一种分割使得每一段都是集合里的元素. 注释:$ ...
- 【HNOI2004】【P1365】L语言
tire水题,%Menci 原题: 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章.一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成. ...
- 「USACO08DEC」「LuoguP2922」秘密消息Secret Message(AC自动机
题目描述 Bessie is leading the cows in an attempt to escape! To do this, the cows are sending secret bin ...
- BZOJ 1212 HNOI2004 L语言 AC自己主动机(Trie树)+动态规划
标题效果:给定词的列表,并m串 每个字符串q个最长前缀,这个前缀可满足拆分成一些字符串 这些字符串中存在的词汇太 再也不怕错误的数据范围--有一个很明显Trie树能解决的问题竟然被我写的AC自己主动机 ...
随机推荐
- Keras使用的一些细节
1.Keras输出的loss,val这些值如何保存到文本中去: Keras中的fit函数会返回一个History对象,它的History.history属性会把之前的那些值全保存在里面,如果有验证集的 ...
- 【转】supervisord使用
Supervisor (http://supervisord.org) 是一个用 Python 写的进程管理工具,可以很方便的用来启动.重启.关闭进程(不仅仅是 Python 进程).除了对单个进程的 ...
- vue2.0 自定义 下拉刷新和上拉加载更多(Scroller) 组件
1.下拉刷新和上拉加载更多组件 Scroller.vue <!-- 下拉刷新 上拉加载更多 组件 --> <template> <div :style="mar ...
- Mina、Netty、Twisted一起学(七):公布/订阅(Publish/Subscribe)
消息传递有非常多种方式.请求/响应(Request/Reply)是最经常使用的.在前面的博文的样例中.非常多都是採用请求/响应的方式.当server接收到消息后,会马上write回写一条消息到clie ...
- js逻辑非同时两次使用 !!null
今天遇到了“!!null”的写法,百度没有找到直接的解释,翻书在<javascript高级设计>P44找到了相应的解释: 同时使用两个逻辑非操作符,实际上就会模拟Boolean()转型函数 ...
- VueJS参数绑定:v-bind:href,v-on:event
参数绑定HTML <!DOCTYPE html> <html> <head> <meta charset="utf-8"> < ...
- Ffmpeg 获取USB Camera 视频流
本文讲述的案例是如何通过Ffmpeg实现从USB Camera中获取视频流并将视频流保存到MP4文件. 本文亦适用于从USB Camera 获取视频流并将视频流转发到rtmp服务的案例,二者基本的原理 ...
- EasyUI基础入门之Droppable(可投掷)
怎么说呢Droppable这个单词究竟是什么意思,准确来说easyui作者究竟要表达什么意思,还是不大好拿捏的.只是没关系,没有必要纠结与这些细枝末节的东西,依据官网的demo效果,就简单的将之定义为 ...
- .Net 平台WebService的创建、部署和使用介绍
.NET平台内建了对Web Service的支持,包括Web Service的构建和使用.与其它开发平台不同,使用.NET平台,你不需要其他的工具或者SDK就可以完成Web Service的开发了.. ...
- Django知识梳理
请求周期: url > 路由 > 函数或类 > 返回字符串或模板语言 Form 表单提交: 先处理模板语言再讲HTML发出去 提交 > url > 函数或类中的方法 — ...