[BZOJ 4259] 残缺的字符串
4259: 残缺的字符串
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2023 Solved: 481
[Submit][Status][Discuss]
Description
很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n。可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺。
你想对这两个串重新进行匹配,其中A为模板串,那么现在问题来了,请回答,对于B的每一个位置i,从这个位置开始连续m个字符形成的子串是否可能与A串完全匹配?
Input
第一行包含两个正整数m,n(1<=m<=n<=300000),分别表示A串和B串的长度。
第二行为一个长度为m的字符串A。
第三行为一个长度为n的字符串B。
两个串均仅由小写字母和*号组成,其中*号表示相应位置已经残缺。
Output
第一行包含一个整数k,表示B串中可以完全匹配A串的位置个数。
若k>0,则第二行输出k个正整数,从小到大依次输出每个可以匹配的开头位置(下标从1开始)。
Sample Input
3 7
a*b
aebr*ob
a*b
aebr*ob
Sample Output
2
1 5
1 5
两个字符串都含通配符
求A在B中出现的所有位置
先把通配符出现的位置赋值为0
然后构造式子$f_i=\sum_{i<=k<=i+n-1}a_ib_i(a_i-b_i)^2$
A在位置$i$出现,当且仅当$f_i=0$
把A翻转就变成卷积形式辣
#include <bits/stdc++.h> using namespace std; const int maxn = 1048576; struct comp{ double x, y; comp(double _x = 0, double _y = 0){ x = _x; y = _y; } friend comp operator * (const comp &a, const comp &b){ return comp(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x); } friend comp operator + (const comp &a, const comp &b){ return comp(a.x + b.x, a.y + b.y); } friend comp operator - (const comp &a, const comp &b){ return comp(a.x - b.x, a.y - b.y); } }f[maxn], g[maxn], ans[maxn]; int rev[maxn]; void dft(comp A[], int len, int kind){ for(int i = 0; i < len; i++){ if(i < rev[i]){ swap(A[i], A[rev[i]]); } } for(int i = 1; i < len; i <<= 1){ comp wn(cos(acos(-1.0) / i), kind * sin(acos(-1.0) / i)); for(int j = 0; j < len; j += (i << 1)){ comp tmp(1, 0); for(int k = 0; k < i; k++){ comp s = A[j + k], t = tmp * A[i + j + k]; A[j + k] = s + t; A[i + j + k] = s - t; tmp = tmp * wn; } } } if(kind == -1) for(int i = 0; i < len; i++) A[i].x /= len; } void init(int &len, int n, int m){ int L = 0; for(len = 1; len < n + m - 1; len <<= 1, L++); for(int i = 0; i < len; i++){ rev[i] = rev[i >> 1] >> 1 | (i & 1) << L - 1; } } char str[300000 + 10]; int a[maxn] = {}, b[maxn] = {}; int cnt = 0, arr[300000 + 10]; int main(){ int n, m, len; scanf("%d %d", &n, &m); init(len, n, m); scanf("%s", str); for(int i = 0; i < n; i++){ if(str[n - i - 1] == '*') a[i] = 0; else a[i] = str[n - i - 1] ^ 96; } scanf("%s", str); for(int i = 0; i < m; i++){ if(str[i] == '*') b[i] = 0; else b[i] = str[i] ^ 96; } for(int i = 0; i < len; i++){ f[i].x = a[i] * a[i] * a[i]; f[i].y = 0; g[i].x = b[i]; g[i].y = 0; } dft(f, len, 1); dft(g, len, 1); for(int i = 0; i < len; i++){ ans[i] = f[i] * g[i]; } for(int i = 0; i < len; i++){ f[i].x = a[i]; f[i].y = 0; g[i].x = b[i] * b[i] * b[i]; g[i].y = 0; } dft(f, len, 1); dft(g, len, 1); for(int i = 0; i < len; i++){ ans[i] = ans[i] + f[i] * g[i]; } for(int i = 0; i < len; i++){ f[i].x = (-2) * a[i] * a[i]; f[i].y = 0; g[i].x = b[i] * b[i]; g[i].y = 0; } dft(f, len, 1); dft(g, len, 1); for(int i = 0; i < len; i++){ ans[i] = ans[i] + f[i] * g[i]; } dft(ans, len, -1); for(int i = n - 1; i <= m - 1; i++){ if(fabs(ans[i].x) < 0.5){ arr[++cnt] = i - n + 2; } } printf("%d\n", cnt); for(int i = 1; i <= cnt; i++){ printf("%d ", arr[i]); } return 0; }