題目描述:
給出字母排列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時一般無法通過。