NOIP模拟赛20191007 T2 好文章【(卡)哈希 / 后缀自动机】

题目描述:

长为n的字符串,找出其中长度为m的不同子串的数量。
1<=m<=n<=200000

题目分析:

显然可以哈希。
但是出题人把我震惊了:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
啪啪啪…(鼓掌)

于是我们知道了自然溢出很危险。。模数109左右更危险。。

所以我们哈希要用两个模数或者用一个超大模数加上大数乘法取模(x*y-(LL)((long double)x/p*y)*p)(模数比如说可以是5211600617818708273ll)

哈希的Code我就不放了,很好写。

我考场上写了后缀自动机来对拍,然而交了自然溢出的哈希上去又没能AK(无法AK的诅咒

后缀自动机的做法就是从起点开始走长度为m的路径,路径条数就是不同的子串个数。但是不能直接走,那样可能退化成O(nm),我们观察自动机的每个节点,它到根虽然有多条路径,但是每条路径长度都是不同且连续的,所以只要它最长路径的长度>=m,它后缀连接指向的节点的最长路径<m,那么它就必然有一条通往起点的长为m的路径,所以可以O(1)判断,总复杂度就是O(n)的。
不过注意后缀自动机的空间是三倍。

Code:

#include<cstdio>
#include<cstring>
#define maxn 600005
int n,m,ans;
char s[maxn];
int last,sz,len[maxn],fail[maxn]={-1},ch[maxn][26];
void sa_extend(int c){
	int cur=++sz,p=last,q; len[last=cur]=len[p]+1;
	for(;p!=-1&&!ch[p][c];p=fail[p]) ch[p][c]=cur;
	if(p==-1) fail[cur]=0;
	else if(len[q=ch[p][c]]==len[p]+1) fail[cur]=q;
	else{
		int clone=++sz;
		len[clone]=len[p]+1,memcpy(ch[clone],ch[q],sizeof ch[q]);
		fail[clone]=fail[q],fail[q]=fail[cur]=clone;
		for(;p!=-1&&ch[p][c]==q;p=fail[p]) ch[p][c]=clone;
	}
}
int main()
{
	scanf("%d%d%s",&n,&m,s);
	for(int i=0;i<n;i++) sa_extend(s[i]-'a');
	for(int i=1;i<=sz;i++) if(len[i]>=m&&len[fail[i]]<m) ans++;
	printf("%d\n",ans);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值