[Luogu P4173] [BZOJ 4259] 殘缺的字串
阿新 • • 發佈:2018-12-12
洛谷傳送門
題目描述
很久很久以前,在你剛剛學習字串匹配的時候,有兩個僅包含小寫字母的字串和,其中串長度為,串長度為。可當你現在再次碰到這兩個串時,這兩個串已經老化了,每個串都有不同程度的殘缺。
你想對這兩個串重新進行匹配,其中為模板串,那麼現在問題來了,請回答,對於的每一個位置,從這個位置開始連續個字元形成的子串是否可能與串完全匹配?
輸入輸出格式
輸入格式:
第一行包含兩個正整數,分別表示串和串的長度。
第二行為一個長度為的字串。
第三行為一個長度為的字串。
兩個串均僅由小寫字母和號組成,其中號表示相應位置已經殘缺。
輸出格式:
第一行包含一個整數,表示串中可以完全匹配串的位置個數。
若,則第二行輸出個正整數,從小到大依次輸出每個可以匹配的開頭位置(下標從開始)。
輸入輸出樣例
輸入樣例#1:
3 7
a*b
aebr*ob
輸出樣例#1:
2
1 5
說明
100%的資料滿足。
解題分析
這種萬用字元匹配的問題也能做, 但顯然要跑一年才能跑出來… 因為字串不全自動機也就了…
所以我們考慮換一種思路, 如果沒有萬用字元匹配的串會滿足 那麼如果有萬用字元的話實際上其的權值設為0就行, 然後我們魔改一下這個式子就行了: 但這玩意還是沒法做, 我們把翻轉一下上面那個式子就變成了一個卷積的形式, 做遍就好了。
程式碼如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <cctype>
#define R register
#define IN inline
#define W while
#define db double
#define MX 2400500
const db PI = std::acos(-1.0);
struct Complex {db im, re;} a[MX], b[MX], c[MX];
IN Complex operator * (const Complex &x, const Complex &y)
{return {x.im * y.re + x.re * y.im, x.re * y.re - x.im * y.im};}
IN Complex operator + (const Complex &x, const Complex &y)
{return {x.im + y.im, x.re + y.re};}
IN Complex operator - (const Complex &x, const Complex &y)
{return {x.im - y.im, x.re - y.re};}
IN Complex operator * (const Complex &x, const db &y)
{return {x.im * y, x.re * y};}
char tar[MX], mod[MX];
int rev[MX], ans[MX];
db v1[MX], v2[MX];
int tot, sum, lg, cnt, len1, len2;
IN void FFT(Complex *dat, const int &typ)
{
for (R int i = 1; i < tot; ++i) if(rev[i] < i) std::swap(dat[rev[i]], dat[i]);
R int cur, seg, bd, step, now; Complex deal, base, buf1, buf2;
for (seg = 1; seg < tot; seg <<= 1)
{
step = seg << 1; base = {std::sin(PI / seg) * typ, std::cos(PI / seg)};
for (now = 0; now < tot; now += step)
{
deal = {0, 1}; bd = now + seg;
for (cur = now; cur < bd; ++cur, deal = deal * base)
{
buf1 = dat[cur], buf2 = dat[cur + seg] * deal;
dat[cur] = buf1 + buf2, dat[cur + seg] = buf1 - buf2;
}
}
}
}
int main(void)
{
scanf("%d%d", &len1, &len2);
scanf("%s%s", tar, mod);
for (R int i = 0; i < len1; ++i) v1[len1 - i - 1] = (tar[i] == '*') ? 0 : tar[i] - 'a' + 1;
for (R int i = 0; i < len2; ++i) v2[i] = (mod[i] == '*') ? 0 : mod[i] - 'a' + 1;
sum = len1 + len2;
for (tot = 1; tot <= sum; tot <<= 1, ++lg); tot <<= 1, ++lg;
for (R int i = 1; i < tot; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));
for (R int i = 0; i < tot; ++i) a[i] = {0, v1[i] * v1[i] * v1[i]}, b[i] = {0, v2[i]};
FFT(a, 1), FFT(b, 1);
for (R int i = 0; i < tot; ++i) c[i] = a[i] * b[i];
for (R int i = 0; i < tot; ++i) a[i] = {0, v1[i] * v1[i]}, b[i] = {0, v2[i] * v2[i]};
FFT(a, 1), FFT(b, 1);
for (R int i = 0; i < tot; ++i) c[i] = c[i] - a[i] * b[i] * 2.0;
for (R int i = 0; i < tot; ++i) a[i] = {0, v1[i]}, b[i] = {0, v2[i] * v2[i] * v2[i]};
FFT(a, 1), FFT(b, 1);
for (R int i = 0; i < tot; ++i) c[i] = c[i] + a[i] * b[i];
FFT(c, -1); int bd = len2 - len1;
for (R int i = 0; i <= bd; ++i) if(fabs(c[i + len1 - 1].re) < 0.5) ans[++cnt] = i + 1;
printf("%d\n", cnt);
for (R int i = 1; i <= cnt; ++i) printf("%d ", ans[i]);
}