[BZOJ 4259] 残缺的字符串

4259: 残缺的字符串

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 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

Sample Output

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

 

posted @ 2019-11-02 15:52  Elder_Giang  阅读(121)  评论(0编辑  收藏  举报