「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自己主动机 ...
随机推荐
- uva 11127(暴力)
题意:给出一个字符串,包含0.1.*,当中×是能够替换成0或者1的,假设字符串的某个子串S有SSS这种连续反复3次出现,不是Triple-free串,问给出的字符串能够形成多少个非Triple-fre ...
- Java太阳系小游戏分析和源代码
Java太阳系小游戏分析和源代码 -20150809 近期看了面向对象的一些知识.然后跟着老师的解说做了一个太阳系各行星绕太阳转的小游戏,来练习巩固一下近期学的知识: 用到知识点:类的继承.方法的重载 ...
- ollydbg快速定位方便调试
在ollydbg调试的时候,会看到大量的汇编代码(远多于源代码),代码中有大量的函数嵌套调用,调试起来周期很长,难度比较大. 所以我们希望能快速定位到代码,以下是快速定位的四种方法: 1.Goto命令 ...
- C语言-回溯例2
组合问题 组合:从n个不同元素中取r个不重复的元素组成一个子集,而不考虑其元素的顺序,称为从n个中取r个的无重组合,例如OR = {1,2,3,4}, n = 4, r = 3则无重组合为: {1,2 ...
- RSA、AES加密解密
RSA #!/usr/bin/env python # -*- coding:utf-8 -*- import rsa import base64 # ######### 1. 生成公钥私钥 #### ...
- 通俗易懂,什么是.NET?什么是.NET Framework?什么是.NET Core? .Net Web开发技术栈
通俗易懂,什么是.NET?什么是.NET Framework?什么是.NET Core? 什么是.NET?什么是.NET Framework?本文将从上往下,循序渐进的介绍一系列相关.NET的概念 ...
- vs2010中添加dll文件
1.更改设置 1.1 project->properties->configuration properties->C/C++->General->Addtional ...
- hdu1878欧拉回路(DFS+欧拉回路)
欧拉回路 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submi ...
- kbmmw 5 的日志备份功能简介
kbmmw 自从4.8.2 版本里增加了日志管理以后,随着版本升级,增加了很多功能,使用方法也有所改变. 功能也越来越强大. 今天说一下 kbmmw5 里面的日志备份,顺便演示一下新的使用方法. 我们 ...
- jquery 备忘笔记
1.选择器 a.查询所有以某字符串开头的元素 $("input[id^='dgItem_txt']") b.获取一组单选按钮中选中的值 $("input[name='it ...