[KMP]匹配长度恰为x的位置数


给你两个串A,B,可以得到从A的任意位开始的子串和B匹配的长度。
给定K个询问,对于每个询问给定一个x,求出匹配长度恰为x的位置有多少个。
N,M,K<=200000

输出
6 2 2
aabcde
ab

2

输出

1

//-----------------------------------------------------------------------------

考虑下面的例子:
A串:abbabbabababbababba
B串:abbabababba

应用KMP算法,很容易得到B串的自我匹配是
元素 a b b a b a b a b b  a
位置 1 2 3 4 5 6 7 8 9 10 11
长度 0 0 0 1 2 1 2 1 2 3  4
这个数组记为kmp[位置] = 匹配长度。

由此求得到A串的各个元素尾部的匹配长度是
a b b a b b a b a b a b b  a  b a b b a
1 2 3 4 5 3 4 5 6 7 8 9 10 11 5 6 7 3 4

统计出各个长度的出现频数
长度 0 1 2 3 4 5 6 7 8 9 10 11
频数 0 1 1 3 3 3 2 2 1 1 1  1
这个数组记作cnt[长度] = 频数。

根据KMP自我匹配数组的性质,如果以A串某个元素结尾有一个长度为11的字串可以与B串匹配的话,以该元素结尾的长度为kmp[11] = 4的字串也是可以匹配的。所以说cnt[4] += cnt[11]。也就是说,进行这样的操作

for (i = N; i >= 1; i--)
    cnt[kmp[i]] += cnt[i];

for i := N downto 1 do
  inc( cnt[ kmp[i] ] , cnt[i] );

之后,cnt[i]中保存的就应该是所有长度为i的匹配字串了。这时cnt数组的状态是

长度 0  1 2 3 4 5 6 7 8 9 10 11
频数 19 8 7 4 4 3 2 2 1 1 1  1

然而题中要求的是“长度恰好为i”的子串的个数,也就是这些字串的下一个字符是不能匹配的。然而,cnt数组中存储的cnt[i],必然包含了cnt[i + 1]及以上的情况。然而这很简单,“长度恰好为i”的字串数量就是cnt[i] - cnt[i + 1],因为cnt[i]中可以扩展的字串必然都包含于cnt[i + 1]。

时间复杂度O(M + N)


#include<iostream>    
#include<string>
#include<cstdio>
using namespace std;   
int c[200010];
int f[200010];
string a,b;
int n,m,k;

void getfail()
{
	for(int i=1;i<m;++i)
	{
		int j=f[i];
		while(j && b[i]!=b[j])j=f[j];
		f[i+1]= b[i]==b[j]? j+1:0;
	}
}

int find()
{
	int j=0;
	for(int i=0;i<n;++i)
	{
		while(j && a[i]!=b[j])j=f[j];
		if(a[i]==b[j])j++;
		c[j]++;
	}
}

int main()    
{
	ios::sync_with_stdio(false);
	cin>>n>>m>>k;
	cin>>a>>b;
	getfail();
	find();
	for(int i=m;i>0;--i)
		c[f[i]]+=c[i];
	for(int i=0;i<=m;++i)
		c[i]-=c[i+1];
	for(int i=1;i<=k;++i)
	{
		int r;
		cin>>r;
		cout<<c[r]<<'\n';
	}
  return 0;    
}    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值