【Luogu】P2292 [HNOI2004]L语言 题解
前置芝士:\(Trie\)字典树
这道题,说是AC自动机,实际上一个\(Trie+\)队列轻松搞定。
首先,我们对所有单词建一棵\(Trie\)。
然后,定义一个空队列\(Q\),初始时把\(-1\)放进去(因为字符串下标从\(0\)开始,待会儿详细叙述原因)。
接着,对于每一篇询问的文章\(T\),进行如下操作:
- 取出队头元素,假设是\(x\)。
- 更新\(ans=\max(ans,x)\)。
- 从\(T[x+1]\)开始枚举,进行\(Trie\)上的匹配。(这也解释了为什么刚开始要把\(-1\)放进去,因为这样才能从\(0\)开始枚举)
- 如果成功匹配\(T[i]\),继续枚举,直到第\(5\)步被执行或者\(i\ge T.length\)。
- 否则,如果发现匹配不了了,立即退出循环,跳回第\(1\)步。
- 如果成功匹配\(T[i]\),并且发现这里有字符串结尾标记,则说明成功匹配了一个单词,把\(i\)放进队尾。(注意:此时不能立即退出,待会儿讲原因)
- 执行\(1-6\)步,直到队列为空。
说明一下第\(6\)步,此时为什么不能直接退出呢?
比如:词典为\(\{what,whatis\}\),文章为\(whatisbalabala\)。
如果直接退出,则匹配到\(i=3\)时就退出了,最后输出答案为\(4\)。(而实际为\(6\))
这样,就可以开心地\(code\)啦:(看完代码不要心急,继续往下看)
#include <bits/stdc++.h>
using namespace std;
int n,m,trie[1000005][26],tot,c[1000005];
char tmp[1000005];
queue<int> q;
inline void addstring(char a[]){//添加字符串
int len=strlen(a),pos=0;
for(int i=0;i<len;i++){
if(!trie[pos][a[i]-'a']){
trie[pos][a[i]-'a']=++tot;
pos=trie[pos][a[i]-'a'];
}
else pos=trie[pos][a[i]-'a'];
}
c[pos]=true;
}
inline int find(char a[]){
memset(flag,0,sizeof(flag));
int len=strlen(a),pos=0,ans=-1;q.push(-1);
while(!q.empty()){
int x=q.front();q.pop();//步骤1
ans=max(ans,x);pos=0;//步骤2
for(int i=x+1;i<len;i++){//步骤3
if(trie[pos][a[i]-'a']) pos=trie[pos][a[i]-'a'];//步骤4
else break;//步骤5
if(c[pos]) q.push(i);//步骤6
}
}
return ans==-1?0:ans+1;//字符串下标以0开始,而题目中以1开始
}
int main(){
scanf("%d%d",&n,&m);
for(register int i=1;i<=n;i++){
scanf("%s",tmp);addstring(tmp);
}
for(register int i=1;i<=m;i++){
scanf("%s",tmp);printf("%d\n",find(tmp));
}
return 0;
}
开心的交上去,咦?怎么只有\(73pts\)?
经不懈思考,终于构造出能卡掉的数据:
字典:\(\{a,aa,aaa,...,aaaaaaaaaa\}\)
文章:\(\underbrace {aaa...aaa}_{10^6个a}\)
于是,对于几乎每个位置\(x\),都被插入队列至少\(10\)次,速度也就呵呵了......
那么,如何防止一个位置被重复插入?很简单,做个标记就行了。
改进后的代码:\((AC)\)
#include <bits/stdc++.h>
using namespace std;
int n,m,trie[1000005][26],tot,c[1000005],flag[1000005];//flag即为标记数组
char tmp[1000005];
queue<int> q;
inline void addstring(char a[]){
int len=strlen(a),pos=0;
for(int i=0;i<len;i++){
if(!trie[pos][a[i]-'a']){
trie[pos][a[i]-'a']=++tot;
pos=trie[pos][a[i]-'a'];
}
else pos=trie[pos][a[i]-'a'];
}
c[pos]=true;
}
inline int find(char a[]){
memset(flag,0,sizeof(flag));//初始化标记数组
int len=strlen(a),pos=0,ans=-1;q.push(-1);
while(!q.empty()){
int x=q.front();q.pop();
ans=max(ans,x);pos=0;
if(flag[x]) continue;//判断一下该位置是否已经有标记了,如果有就continue
if(x!=-1) flag[x]=1;//否则做个标记
for(int i=x+1;i<len;i++){
if(trie[pos][a[i]-'a']) pos=trie[pos][a[i]-'a'];
else break;
if(c[pos]) q.push(i);
}
}
return ans==-1?0:ans+1;
}
int main(){
scanf("%d%d",&n,&m);
for(register int i=1;i<=n;i++){
scanf("%s",tmp);addstring(tmp);
}
for(register int i=1;i<=m;i++){
scanf("%s",tmp);printf("%d\n",find(tmp));
}
return 0;
}//开心的结束
最后,蒟蒻写博客不易,恳请大佬点个赞!
【Luogu】P2292 [HNOI2004]L语言 题解的更多相关文章
- Luogu P2292 [HNOI2004]L语言(Trie+dp)
P2292 [HNOI2004]L语言 题面 题目描述 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章 \(T\) 是由若干小写字母构成. ...
- Luogu P2292 [HNOI2004]L语言
题目链接 \(Click\) \(Here\) 好久没写\(DP\)了真是水平下降不少,一眼把这个题搞成贪心了,然后一发交上只有\(37\)分\(QwQ\) 这个题好像还可以\(AC\)自动机胡搞?不 ...
- 洛谷:P2292 [HNOI2004]L语言(DP+Trie树)
P2292 [HNOI2004]L语言 题目链接:https://www.luogu.org/problemnew/show/P2292 题目描述 标点符号的出现晚于文字的出现,所以以前的语言都是没有 ...
- 2021.11.09 P2292 [HNOI2004]L语言(trie树+AC自动机)
2021.11.09 P2292 [HNOI2004]L语言(trie树+AC自动机) https://www.luogu.com.cn/problem/P2292 题意: 标点符号的出现晚于文字的出 ...
- 洛谷 P2292 [HNOI2004] L语言 解题报告
P2292 [HNOI2004] L语言 题目描述 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章\(T\)是由若干小写字母构成.一个单词 ...
- 洛谷(cogs 1293/bzoj 1212) P2292 [HNOI2004]L语言
1293. [HNOI2004] L语言 ★★★ 输入文件:language.in 输出文件:language.out 简单对比时间限制:1 s 内存限制:162 MB [题目描述] ...
- P2292 [HNOI2004]L语言
传送门 思路: 毒瘤的字典树! ▲主要分有两个步骤: ① 日常的建树. ② 暴力地求解. ▲日常建树:过于基础,跳过. ▲重点在于如何暴力地求解而不被卡掉(DP?不存在的) 可以利用区间动规的思想, ...
- 洛谷P2292 [HNOI2004]L语言
传送门 建好trie树 当$dp[j]==1$当且仅当存在$dp[k]=1$且$T[k+1,j]==word[i]$ 然后乱搞就行了 //minamoto #include<iostream&g ...
- 洛谷 P2292 [HNOI2004]L语言
题目描述 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成.一个字典D是若干个单词的 ...
随机推荐
- LVM的简单使用及常用的命令总结
Lvm的简单使用及常用的命令总结 centos7中默认使用的是xfs文件系统,此文件系统的特点,可以另外查找资料,这里说一下对文件系统的扩容: 1.先看一下没扩容之前的分区大小 2.添加一块新磁盘,并 ...
- 获取豆瓣读书所有热门标签并保存到mongodb数据库
目标url:https://book.douban.com/tag/?view=type&icn=index-sorttags-all 目的:抓取所有标签名称(tag_name),标签链接(t ...
- MCU(Micro Control Unit)中文名称为微控制单元
参考:http://www.elecfans.com/dianzichangshi/mcu.html 什么是mcu_mcu是什么意思 标签:MCU(471)单片机(3098)微控制器(503) MCU ...
- Lane-Detection 近期车道线检测论文阅读总结
近期阅读的几篇关于车道线检测的论文总结. 1. 车道线检测任务需求分析 1.1 问题分析 针对车道线检测任务,需要明确的问题包括: (1)如何对车道线建模,即用什么方式来表示车道线. 从应用的角度来说 ...
- Java中的对象都是在堆上分配的吗?
作者:LittleMagic https://www.jianshu.com/p/8377e09971b8 为了防止歧义,可以换个说法: Java对象实例和数组元素都是在堆上分配内存的吗? 答:不一定 ...
- 硬盘安装Linux
准备材料:U盘.Linux镜像.UltraISO 1.下载安装UltraISO, 2.打开系统镜像 打开后我们就可以在左边侧栏看到镜像的内容 3.插入U盘,点击:启动->写入光盘映像->选 ...
- ansible-主机清单的配置
1. ansible主机清单的配置 以下是ansible安装完成后的源文件 1 [root@test-1 ~]# cat /etc/ansible/hosts 2 # This is the defa ...
- 多测师讲解pthon _函数__return_高级讲师肖sir
#函数中的返回的作用(return) 案例: #函数中的返回的作用:def fun(): #定义的一个函数 num =100 a=num/2 #print(a) #50.0 return a # pr ...
- 请求https接口时报错:Caused by SSLError(SSLError(1, u'[SSL: CERTIFICATE_VERIFY_FAILED] certificat,安装certifi
如何解决SSL 根证书验错误: 一种解决方法是:verify=False 在session.request 里面: session.post(post_url,data=post_data,heade ...
- 【不知道怎么分类】CF 819B Mister B and PR Shifts
题目内容 洛谷链接 定义一个全排列\(p_i\)的偏移值为\(\sum_{i=1}^{n}|p[i]-i|\). 给你一个全排列,你可以从后面拿\(k\in[0,n-1]\)个数放在前面,使得该全排列 ...