bzoj4259 殘缺的字串 FFT

2022-08-05 05:57:11 字數 1584 閱讀 7962

很久很久以前,在你剛剛學習字串匹配的時候,有兩個僅包含小寫字母的字串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

帶萬用字元還要求每一位能不能匹配,那就是fft題啦。

我們把\(*\)始終視為0,然後冷靜分析一下:

因為fft的卷積是乘積相加的形式,我們無法直接用減法,而是要轉化成乘法,所以我們對於原式平方一下,得到:

\(\sum(a_i-b_i)^2=\sum a_i^2*[b_i>0]+\sum b_i^2*[a_i>0]-2*\sum a_ib_i\)

翻轉其中乙個串之後,就可以fft了。

#include #define pi acos(-1)

using namespace std;

int i,j,k,n,m,len,a[1048577],b[1048577],ans[1048577],tot;char aa[1048577],bb[1048577];

struct cp

cp operator +(const cp a)const

cp operator -(const cp a)const

cp operator *(const cp a)const

}w,wn,t,a[1048577],b[1048577],c[1048577];

void fft(cp *a,int n,int op)

for(k=2,wn=cp(cos(2*pi*op/k),sin(2*pi*op/k));k<=n;k<<=1,wn=cp(cos(2*pi*op/k),sin(2*pi*op/k)))

for(i=0,w=cp(1,0);i>1);j++,w=w*wn)

t=w*a[i+j+(k>>1)],a[i+j+(k>>1)]=a[i+j]-t,a[i+j]=a[i+j]+t;

if(op==-1) for(int i=0;i0,0);

for(fft(a,len,1),fft(b,len,1),i=0;i0,0),b[i]=cp(b[i]*b[i],0);

for(fft(a,len,1),fft(b,len,1),i=0;ifor(i=0;ifor(fft(a,len,1),fft(b,len,1),i=0;ifor(fft(c,len,-1),i=m-1;ifor(printf("%d\n%d",tot,ans[1]),i=2;i<=tot;i++) printf(" %d",ans[i]);

}

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...