「刷题」你的名字

题真好。
也帮我回忆起了快两个月没动的\(SAM\)
我只能想到\(68\)分的数据。
题目要求给出一个串\(S\)
然后每次询问给出一个串\(T\)和两个变量\(l,r\)
要求出有多少个本质不同串是\(T\)的子串而不是\(S[l,r]\)的子串。
前面\(68\)分是\(l=1,r=n\)的。
直接做。
首先我们对\(S\)建出后缀自动机。
询问的时候,对\(T\)再次建出后缀自动机。
每次建出一个前缀节点的时候统计一下本质不同子串,同时记录此时前缀节点父亲的\(len\)值,如果是第\(i\)个前缀节点,那么这个值称作\(t[i]\)
这样就简单了。
我们在\(S\)\(SAM\)上跑\(T\)
每次跑到某一个节点的时候就判断一下当前的匹配长度\(len\)是否大于当前的\(t[i]\)值。
这样用\(T\)本质不同子串减去\(len-t[i]\),表示当前匹配到的长度所被包含的最长后缀中含有的可以匹配上的本质不同子串的个数。
这样就得到答案了。

剩下的32分想不到了。

正解是用线段树合并去做。
我们首先建出\(S\)\(SAM\)
这样用线段树合并求出\(endpos\)集合。
同样在\(S\)上跑\(T\)
这次判断条件改一下。
能否匹配的条件是转移过去的节点的\(endpos\)集合和\([L+len,R]\)有交。
注意此时失配不能直接跳虚树父亲节点,而应当减小\(len\)在试一次。
这样用二分即可,复杂度多出一个\(log\)。(10^6俩\(log\)都能卡过\(hhh\)
同样做法减去\(len-t[i]\)就可以了。

你可能感兴趣的:(「刷题」你的名字)