「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自己主动机 ...
随机推荐
- NFC模组,开发NFC功能 仅仅要几条指令的事情
特点:实现NFC透明传输.内置NFC协议栈,支持UART串口直接读写,用于门禁能够同一时候兼容手机和卡片开门,还能实现动态密钥,读到的NFC数据自己主动串口输出,会串口就能开发NFC,不须要研究LLC ...
- 赵雅智_Fragment
当我们须要动态的多界面切换的时候,就须要将UI元素和Activity融合成一个模块. 在2.3中我们一般通过各种Activity中进行跳转来实现多界面的跳转和单个界面动态改变.在4.0或以上系统中就能 ...
- OS: 读者写者问题(写者优先+LINUX+多线程+互斥量+代码)(转)
一. 引子 最近想自己写个简单的 WEB SERVER ,为了先练练手,熟悉下在LINUX系统使用基本的进程.线程.互斥等,就拿以前学过的 OS 问题开开刀啦.记得当年学读者写者问题,尤其是写者优先的 ...
- Codeforces Round #267 (Div. 2) B. Fedor and New Game
After you had helped George and Alex to move in the dorm, they went to help their friend Fedor play ...
- cvpr2017-code-etc
cvpr2017: code: http://staffhome.ecm.uwa.edu.au/~00053650/code.html
- bootstrap table api
http://blog.csdn.net/rickiyeat/article/details/56483577
- 安装protobuf可能遇到的问题
下载protobuf-2.3.0: http://protobuf.googlecode.com/files/protobuf-2.3.0.zip http://code.google.com/ ...
- 使用Apache Commons Chain(转载)
原博客出处:http://phil-xzh.iteye.com/blog/321536 使用Commons Chain 作为程序开发人员,我们经常需要对一个实际上程序性的系统应用面向对象的方法.商业分 ...
- “ 不确定 "限制值的使用
前言 前篇文章解释了限制值的五种类型以及获取它们的方法.但是对于其中可能不确定的类型( 45类型 ),当限制值获取函数返回-1的时候,我们无法仅通过这个函数返回值-1来判断是限制值获取失败还是限制值是 ...
- Requires: libstdc++.so.6(GLIBCXX_3.4.15)(64bit)
Error: Package: mysql-community-server-8.0.12-1.el7.x86_64 (mysql80-community) Requires: libstdc++.s ...