6881. 【2020.11.21提高组模拟】T3 是我的你不要抢(string)

6 篇文章 1 订阅
2 篇文章 0 订阅

Description

ω 有很多字符串,它们都由小写字母构成。
给你 n 个字符串 a i ,和 Q 个询问,每次对两个串 S = a i , T = a j 询问最大的 L (0 L ≤ | S | ) 使得
S [ n n L + 1 . . . | S | ] = T [1 . . . L ]

Input

从文件 string.in 中读入数据。
第一行两个正整数 n, Q ,表示一共有 n 个字符串,以及有 Q 个询问。
下面 n 行,每行一个字符串 a i
下面 Q 行,每行两个正整数 x, y ,表示询问 S = a x T = a y

Output

输出到文件 string.out 中。
输出 Q 行,每行一个非负整数,表示最大的 L

Sample input

3 6
wwq
eew
qwe
1 2
2 3
1 3
2 1
3 2
3 1

Sample Output

0
0
1
1
1
0
【样例 2
见选手目录下的 string/string2.in string/string2.ans
该样例满足第二档部分分的性质。
【样例 3
见选手目录下的 string/string3.in string/string3.ans
该样例满足第三档部分分的性质。
【样例 4
见选手目录下的 string/string4.in string/string4.ans
该样例满足第四档部分分的性质。

Data Constraint

 

Solutoin

对于每一个字符串处理出其字符串哈希值。

暴力扫描即可,对于n<200的直接记录答案。

法一:

对于小于根号L的直接暴力求,对于大于根号L的只有少于根号L个,记录下来。

时间复杂度O(QL^{1/2})

对于长度大于等于 √ L 的只有 O( √ L) 个,处理它们两两之间答案。 否则只要存在一个长度小于 √ L 的,就可以直接 O( √ L) 比较。 复杂度 O((L + Q) √ L),期望得分 70 ∼ 100。 3 调一下块大小能够做到 O(L √ Q)。 由于出题人忘记造到 trie 上了,没有体现更好的区分度在此谢罪。

法二:

如果把所有串建出 AC 自动机。设 B 满足 S = S ′ + B,T = B + T ′,则 S 在 fail 树上到祖先链里恰好有 B。 我们要最大化这个 B,其实是要求 trie 树上根到 T 的链,与 fail 树上,根到 S 的链,并的深度最大的节点。 将问题离线,在 trie 上 dfs,每次把当前点的信息加入数据结构,dfs 到 T 处 时查询 S 处的答案。 直接使用树链剖分,时间复杂度 O(n log2 n),期望得分 70 ∼ 100。 考虑我们的操作只是子树 max,单点查询,考虑标记永久化后使用可回退数据 结构。时间复杂度 O(n log n),期望得分 100。

Code 

#include<cstdio> 
#include<cstring>
#include<algorithm>
#include<string>
#include<cmath>
#define I int
#define llu unsigned long long
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define N 600060
using namespace std;
char s[N],c;
I n,Q,x,y,ans,len,st[N],ed[N],bz[5020][5020];
llu pre[N],suf[N],p=131,now;
I R(I &x){
	x=0;I w=1;c=getchar();
	while(c<'0'||c>'9'){if(c=='-') w=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	return x*=w;
}
I pd(){return suf[ed[x]-ans+1]==pre[st[y]+ans-1];}
I main(){
	freopen("string.in","r",stdin);
	freopen("string.out","w",stdout);
	R(n),R(Q);
	F(i,1,n){
		c=getchar();
		while(c<'a'||c>'z') c=getchar();
		while(c>='a'&&c<='z'){
			s[++len]=c;
			c=getchar();
		}
		st[i]=ed[i-1]+1,ed[i]=len;
		pre[st[i]]=s[st[i]]-'a'+1;
		F(j,st[i]+1,ed[i]) pre[j]=pre[j-1]*p+s[j]-'a'+1;	
		suf[ed[i]]=s[ed[i]]-'a'+1;now=p;
		Fd(j,ed[i]-1,st[i]){suf[j]=suf[j+1]+(s[j]-'a'+1)*now;now*=p;}
	}
	memset(bz,255,sizeof bz);
	while(Q--){
		R(x),R(y);
		if(x<=5000&&y<=5000&&bz[x][y]!=-1){printf("%d\n",bz[x][y]);continue;}
		ans=min(ed[x]-st[x]+1,ed[y]-st[y]+1);
		while(!pd()&&ans) ans--;
		printf("%d\n",ans);
		if(x<=5000&&y<=5000) bz[x][y]=ans;
	}
	return 0;
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值