Link
对我来说算神题了
Solution
先考虑暴力做法
枚举每个与模式串的最后一个颜色相同的点,判断是否合法。
判断方法是从这个点向两边分别贪心地匹配两个模式串,找到一个最靠右的左串匹配位置,和最靠左的右串匹配位置。然后在和中找一下是否有两个颜色相同的点。至于找相同,一种方法就是遍历,把途径的颜色用bool[]标记,然后再遍历。
可以看出,这样又做了很多无用功,因为很有可能连续的一段区间,向左右匹配的位置都是相同的。这样就不好了。
所以考虑对这个量进行预处理。然后我就怎么也想不出来了。研究一番Claris巨神的代码,并看不懂复杂度。写完A掉之后,忽然灵光一现,不禁拍案叫绝。
设原序列为,左模式串的序列为。假设当前在计算,表示使得的中存在一个子序列,且最大的,设表示在中的第一个颜色的位置,表示序列中下一个与颜色相同的位置。
外层循环从枚举的每一个位置,设表示使得能成功匹配的最大的。
然后循环这样做:
(在代码中,)
1
2
3
4
5
6
7
8
9
10
11
12
13for(int i=1;i<=n;++i) {
ls[i]=f[1];
if(c[i]==x[lx]) {
f[lx]=i;
for(int u,p=lx-1;p;--p) {
if((u=(f[p]?next[f[p]]:first[x[p]]))<f[p+1]) {
do f[p]=u;
while((u=(f[p]?next[f[p]]:first[x[p]]))<f[p+1]);
} else
break;
}
}
}
如果的倒数第二个字符与相同,那就更新。然后从开始枚举,将挪到最后一个在之前的颜色为的位置。 复杂度? 设在中出现了次,那么至多会向后移动次。而的元素互异,那么复杂度就是 处理出来之后,可以发现,随着枚举点右移,和都是单调不降的。因此可以类比莫队,实现计算。 记得特判模式串为的情况
Tips
唯有泪千行。。 KMP--一个指针的均摊-- 双指针--两个指针的均摊-- K指针--K个指针的均摊-- 只注意到了匹配的第一个点位置的单调性,但没有进一步观察所有点位置的单调性
Code
1 |
|