• [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
    ", cnt);
        for(int i = 1; i <= cnt; i++){
            printf("%d ", arr[i]);
        }
        return 0;
    } 
  • 相关阅读:
    优秀的 Java 项目,代码都是如何分层的?
    计算机应届生月薪大多是多少?
    零基础要怎么学JAVA?
    自学 Java 怎么入门?
    Java学习路线总结,已Get腾讯Offer
    java培训出来的如何找工作?
    离散数学学习笔记
    一些公式
    一个模拟
    秦皇岛wannafly[数论]学习笔记
  • 原文地址:https://www.cnblogs.com/ruoruoruo/p/11782647.html
Copyright © 2020-2023  润新知