【JZOJ5795】词典

Description

Input

第一行两个数n,m,表示有n个字符串,m个询问。
接下来n行,每行一个字符串Ti 。
再接下来m行,每行一个字符串Si 。

Output

对于每个询问,输出一个ansi表示答案。

Sample Input

3 2
abcabc
aabc
abbc
aa
ba  

Sample Output

1
3 

Data Constraint

题解:

考试时听别人说是哈希,然后赶紧学了一波字符串哈希,打了一波暴力,然后直接BL
看题解是Trie,然后赶紧学了一波Trie,在他们还在苦苦纠结第一题的时候,我第一个打出了第二题,膨胀了一波
好吧如果知道Trie的话这道题还是很简单的,然而这样的基本数据结构我都还不会= =,都是现学现卖的
我们先对n个标准串建一个Trie,在建Trie的同时,在一个节点用一个Vector存建树过程中经过这个点的标准串序号
比如说abc和ab两个串建Trie,a下面的b节点存入了1和2,b下面的c节点存入了2
然后我们对于一次询问,如果我们能匹配,那么我们取出最后一个匹配点的Vector,在这个Vector内保存的就是
能够和询问串匹配的标准串的编号了,根据这个编号我们很容易能得出最长的0串
然而用Vector会MLE。考虑算0串时的过程,我们每次将相邻两个序号相减与Ans比较,也就是说
我们只需要当前的一个序号和上一个序号就能更新答案
于是我们弃用Vector,用一个结构体保存上一个经过这个点的标准串序号,以及最长0串长度
每一次插入操作时,若再次经过某个点,我们算出这个标准串序号与上一次经过这个点的标准串序号的差减一
即中间夹着的0的个数,用它来更新Ans,注意处理首个1前面的0和最后一个1后面的0单独处理

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<climits>
#include<iomanip>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define MAXA 5000005
#define ipt(x) scanf("%d",&x)
using namespace std;
typedef long long LL;
struct Rx {
	int Last;
	int Ans;
}Pass[MAXA];
int n,m,tot = 1,Trie[MAXA][3],Ans,LastLen;
char Temp[MAXA];
void Insert(char *s,int k) {
	int Len = strlen(s),Now = 1;
	for(int i=0;i<Len;i++) {
		int edge = s[i] - 'a';
		if(Trie[Now][edge] == 0)
		   Trie[Now][edge] = ++tot;
		Now = Trie[Now][edge];
		if(Pass[Now].Last == 0) {
			Pass[Now].Ans = k - 1;
			Pass[Now].Last = k;
		}
		else {
			Pass[Now].Ans = max(Pass[Now].Ans,k - Pass[Now].Last - 1);
			Pass[Now].Last = k;
		}
	}
}
void Search(char *s) {
	int Len = strlen(s),Now = 1;
	for(int i=0;i<Len;i++) {
		Now = Trie[Now][s[i]-'a'];
		if(Now == 0) {
			Ans = n;
			return;
		}
	}
	Ans = 0;
	Ans = max(n - Pass[Now].Last,Pass[Now].Ans);
}
int main() {
//	freopen("word.in","r",stdin);
//	freopen("word.out","w",stdout);
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++) {
		scanf("%s",Temp);
		Insert(Temp,i);
	}
	for(int i=1;i<=m;i++) {
		scanf("%s",Temp);
		Search(Temp);
		printf("%d\n",Ans);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值