题目大意及模型转换
给定一个长度为n(n<=3*10^5)的文本串与m(m<=5000)个长度不超过5000的模板。现在将m个模板与文本串进行匹配,输出不可能被匹配到的字符有多少个。
模拟题意
对于字符串匹配的题目,我们可以很快想到kmp算法。
我们可以对每一个模板做kmp算法,然后将每一个模板和文本串做匹配。匹配到的打上布尔标记。
不过,这样会超时,因为匹配的复杂度太大了。
两种方法
想想,还有什么字符串匹配算法?
对文本串进行处理的后缀数组。
对多模板进行处理的AC自动机。
后缀数组
我们求出sa数组后,对于每一个模板,一个字符一个字符逼进。假设目前到第i个字符,排序后的后缀区间l..r中所有后缀前i-1个字符都与该模板前i-1个字符相同。那么我们在区间l..r中寻找新的区间l’..r’,使得l’..r’中所有后缀都与该模板前i个字符相同。然后做完后得到的后缀区间就是匹配成功的地方。
AC自动机
既然是AC自动机那就是裸题了,不讲了。具体实现我们在每个结点上记录深度,这样可以得到匹配成功后的开始位置。
不会AC自动机?戳这里:AC自动洗学习小记by Crazy
统计答案
我们打布尔标记很慢的,怎么办?
我们可以设c[i]表示在i这个位置开始被匹配成功,一直被匹配到i+c[i]-1。
c[i]=0则表示后缀i不存在任何一个前缀能被任意一个模板匹配。
于是就可以了。
t:=0;
for i:=1 to n do
begin
if t>0 then dec(t);
if c[rank[i]]>t then t:=c[rank[i]];
if t=0 then inc(ans);
end;
writeln(ans);