description
很久很久以前,在你剛剛學習字串匹配的時候,有兩個僅包含小寫字母的字串a和b,其中a串長度為m,b串長度為n。可當你現在再次碰到這兩個串時,這兩個串已經老化了,每個串都有不同程度的殘缺。
你想對這兩個串重新進行匹配,其中a為模板串,那麼現在問題來了,請回答,對於b的每乙個位置i,從這個位置開始連續m個字元形成的子串是否可能與a串完全匹配?
第一行包含兩個正整數m,n(1<=m<=n<=300000),分別表示a串和b串的長度。
第二行為乙個長度為m的字串a。
第三行為乙個長度為n的字串b。
兩個串均僅由小寫字母和號組成,其中號表示相應位置已經殘缺。
第一行包含乙個整數k,表示b串中可以完全匹配a串的位置個數。
若k>0,則第二行輸出k個正整數,從小到大依次輸出每個可以匹配的開頭位置(下標從1開始)。
3 7ab
aebrob
21 5
首先帶萬用字元的字串匹配好像不能\(kmp\)。
這是\(ntt/fft\)的乙個經典應用。
如果\(a[i]與b[j]\)不能匹配,那麼\(j-i+1\)就不能作為匹配的開頭位置。
所以我們設乙個函式\(\displaystyle gg(x)=\sum_^n\sum_^m[j-i+1==x]\cdot [a[i]與b[j]不能匹配]\)。我們發現這個函式有點像乙個卷積的形式。於是我們將第乙個字串翻轉(因為是\(-i\)),然後關鍵在於怎麼構造卷積來使得不同的字元對\(gg\)函式有貢獻。
我們將萬用字元位置的值設為0,其他的設為其在字元表中的序號。然後
\[\begin
\displaystyle gg(x)&=\sum_^n\sum_^m[j-i+1==x]\cdot (a[i]-b[j])^2a[i]b[j]\\
&=\sum_^n\sum_^m[j-i+1==x]\cdot(a[i]^3b[j]-2a[i]^2b[j]^2+a[i]b[j]^3)
\end
\]然後我們做3次fft就可以了。
**:
#include#define ll long long
#define n 300005
#define z complex#define pi acos(-1)
#define mod 998244353
using namespace std;
inline int get() while('0'<=ch&&ch<='9') return x*f;}
int n,m;
char s[n],t[n];
int x[n],y[n];
z f[n<<2],g[n<<2];
int rev[n<<2];
void fft(z *a,int d,int flag)
ll cal3(ll a)
int main()
BZOJ4259 殘缺的字串
給出兩個字串,乙個模式串,乙個匹配串,問匹配串中哪些位置可以匹配上模式串,其中 可以作任意字元。這個可以轉化為多項式,我們可以把 看作0,其他字母看作各個數字,然後發現如果兩個字串相同,當且僅當 i 0n 1 a i b i 2 a i b i 0 sum 0 i 0n 1 a i b i 2 a ...
BZOJ4259 殘缺的字串
其實大部分字串的題都可以用多項式來想,包括這道題。於是,我們可以嘗試去構造兩個多項式,使其乘後的係數為0即可。相等為0,那麼我們可以用減法表示。可 可以匹配所有的符號,我們又該咋辦?那不就相當於乘個0嘛。於是,我們得到了下式 然後就可以卷積計算了。include include include in...
bzoj 4259 殘缺的字串
這題好神啊,居然是fft,表示一直在往資料結構上想。把 當成0,那麼兩個串可以匹配當且僅當 sum a i b i 2 times a i times b i 0 我們可以把平方拆開,然後就變成了幾個乘積相加的形式,那就大力翻轉乙個串然後跑fft。因為最開始mle了所以複製貼上了好多東西。1 inc...