题目描述:
给出字母排列p以及字符串s,t
s中的字符c可以匹配t中的c和pc,求s在t中的出现位置。
n≤2∗105
题目描述:
法一:枚举字符累加匹配数
枚举一个字符c,将s中为c的位置设为1,t中匹配的位置设为1,然后做卷积。
每个字符都做完后 i 位置的值就是[i−∣s∣+1,i]匹配s的位置个数,检验是否等于∣s∣即可。
复杂度O(∑∗nlogn),∑是字符集大小,这里是26。
不太能过,可以虚数部分利用起来减小2的常数。
法二:差异计算式求和
将每个位置的匹配信息写作一个计算式,当且仅当匹配时为0,其余时候为正数,那么就只需要检验最后对应位置的和是否为0即可。
此题中s匹配t[l,r]计算式为 ∑i=0r−l(si−tl+i)2∗(psi−tl+i)2,将平方拆开之后做FFT。
拆开之后每一项形如 coef∗(sia∗psib)∗tl+ic,总共需要 9 次FFT 以及 2 个前缀和。
upd:实际上可以根据两个位置的幂次和来FFT,比如把a+b相同的合并在一起,然后乘上对应的c,这样只需要做 3 次FFT 和 2 个前缀和。
复杂度O(nlogn∗C),C是计算式决定的常数。
如果将FFT改写为NTT,由于是在模意义下,可能被卡。可以选择取两个模数;或者更简便的方法是将字符随机一个[0,mod)以内的权值,这样做的话甚至可以把计算式中的平方给去掉(相当于是在哈希了)。
法三:枚举字符bitset匹配
FFT和bitset其实是在做差不多的事情,对每个字符预处理出一个bitset T[c]表示c字符在 t 中的出现位置,然后求出这个字符在 t 中的匹配位置 match[c]。在此题中 mat[c]=T[c] ∣ T[pc]
然后用一个bitset ans记录每个位置对s的前i个字符是否匹配,每次添加s[i]时,令ans&=match[s[i]]>>i,最后ans的第i位为1就代表[i,i+∣s∣−1]和s匹配了。
复杂度O(预处理+wnm),这个算法当n≥105时一般无法通过。