CF963D Frequency of String【多串在母串的出现位置】

题目描述:

在这里插入图片描述
保证 mim_i 互不相同。

题目分析:

mim_iss 中的匹配次数是 O(Smi)O(|S|*\sqrt {\sum {m_i}}) 级别的。
证明可以用AC自动机来理解,设fail树上每个点的祖先中结束节点的个数为 xx,因为长度各不相同,所以总长度至少为 x(x+1)2\frac {x(x+1)}2,所以 xmix\le \sqrt {\sum {m_i}}。总共会遍历 S|S| 个点的祖先。

原问题相当于是求所有匹配位置中相隔 kk 个的最近距离,求出所有匹配位置之后扫一遍即可。复杂度有保证。

求匹配位置可以 bitset。O(nmiw)O(\frac {n\sum m_i}w)
也可以AC自动机,预处理fail树上第一个有结束节点的祖先 FailFail,用 ss 在自动机上走,每次跳 FailFail,把遇到的结束节点压进对应的栈中,顺便就可以求答案。O(n+nmi)O(n+n\sqrt{\sum m_i})

Code:

#include<bits/stdc++.h>
#define maxn 100005
using namespace std;
int n,m,Q;
char s[maxn],t[maxn];
bitset<maxn>a[26],ans;
int main()
{
	scanf("%s%d",s,&Q),n=strlen(s);
	for(int i=0;i<n;i++) a[s[i]-'a'].set(i);
	for(int k,sz;Q--;){
		scanf("%d%s",&k,t),m=strlen(t);
		ans.set();
		for(int i=0;i<m;i++) ans&=a[t[i]-'a']>>i;
		if((sz=ans.count())<k) {puts("-1");continue;}
		int len=maxn,l=ans._Find_first(),r=ans._Find_first();
		for(int i=1;i<k;i++) r=ans._Find_next(r);
		for(int i=k;i<=sz;i++) len=min(len,r-l+m),l=ans._Find_next(l),r=ans._Find_next(r);
		printf("%d\n",len);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章