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;
}