zoukankan      html  css  js  c++  java
  • P4173 残缺的字符串 (带通配符的FFT字符匹配)

    题目描述

    很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串AAA和BBB,其中AAA串长度为mmm,BBB串长度为nnn。可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺。

    你想对这两个串重新进行匹配,其中AAA为模板串,那么现在问题来了,请回答,对于BBB的每一个位置iii,从这个位置开始连续mmm个字符形成的子串是否可能与AAA串完全匹配?

    输入输出格式

    输入格式:

    第一行包含两个正整数mmm,nnn,分别表示AAA串和BBB串的长度。

    第二行为一个长度为mmm的字符串AAA。

    第三行为一个长度为nnn的字符串BBB。

    两个串均仅由小写字母和*号组成,其中*号表示相应位置已经残缺。

    输出格式:

    第一行包含一个整数kkk,表示BBB串中可以完全匹配AAA串的位置个数。

    k>0k > 0k>0,则第二行输出kkk个正整数,从小到大依次输出每个可以匹配的开头位置(下标从111开始)。

    输入输出样例

    输入样例#1: 复制
    3 7
    a*b
    aebr*ob
    输出样例#1: 复制
    2
    1 5

    说明

    100100100%的数据满足1≤m≤n≤3000001 leq m leq n leq 3000001mn300000。







    定义卷积和为0则完全匹配

    无通配符:
    P(x)=∑[A(i)−B(x−m+i+1)]^2

    *********************************************************************
    有通配符:
    我们设通配符的数值为0
    P(x)=∑[A(i)−B(x−m+i+1)]^2 * A(i) * B(x−m+i+1)
    把平方拆开,会出现三个卷积的形式

    套路的把a翻转,

    fft计算就行了






     1 #include <algorithm>
     2 #include <cmath>
     3 #include <cstdio>
     4 #include <queue>
     5 
     6 typedef double D;
     7 const D P = acos(-1);
     8 const int N = 2e6 + 62;
     9 
    10 struct $ {
    11     D x, y;
    12     inline $(D x_ = 0, D y_ = 0) : x(x_), y(y_) {}
    13     inline $ operator+(const $& rhs) const { return $(x + rhs.x, y + rhs.y); }
    14     inline $ operator-(const $& rhs) const { return $(x - rhs.x, y - rhs.y); }
    15     inline $ operator*(const $& rhs) const { return $(x * rhs.x - y * rhs.y, x * rhs.y + y * rhs.x); }
    16     inline $ operator/(D rhs) const { return $(x / rhs, y / rhs); }
    17 };
    18 
    19 int lim, l, r[N];
    20 void fft($* a, int op) {
    21     for (int i = 0; i < lim; i++)
    22         if (i < r[i]) std::swap(a[i], a[r[i]]);
    23     for (int i = 1; i < lim; i <<= 1) {
    24         $ wn(cos(P / i), op * sin(P / i));
    25         for (int j = 0; j < lim; j += i << 1) {
    26             $ w(1);
    27             for (int k = 0; k < i; k++, w = w * wn) {
    28                 $ x = a[j + k], y = w * a[i + j + k];
    29                 a[j + k] = x + y;
    30                 a[i + j + k] = x - y;
    31             }
    32         }
    33     }
    34     if (op == -1)
    35         for (int i = 0; i < lim; i++) a[i] = a[i] / lim;
    36 }
    37 
    38 $ a2[N], b2[N], c[N];
    39 int m, n, a[N], b[N];
    40 std::queue<int> q;
    41 char s1[N], s2[N];
    42 int main() {
    43     scanf("%d%d%s%s", &m, &n, s1, s2);
    44     for (lim = 1; lim < n * 2; lim <<= 1) l++;
    45     for (int i = 1; i < lim; i++) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
    46     for (int i = 0; i < m; i++)
    47         if (s1[m - i - 1] != '*') a[i] = s1[m - i - 1] - 'a' + 1;
    48     for (int i = 0; i < n; i++)
    49         if (s2[i] != '*') b[i] = s2[i] - 'a' + 1;
    50 
    51     for (int i = 0; i < m; i++) a2[i] = $(a[i] * a[i] * a[i]);
    52     for (int i = 0; i < n; i++) b2[i] = $(b[i]);
    53     fft(a2, 1), fft(b2, 1);
    54     for (int i = 0; i < lim; i++) c[i] = a2[i] * b2[i];
    55 
    56     for (int i = 0; i < lim; i++) a2[i] = b2[i] = $();
    57     for (int i = 0; i < m; i++) a2[i] = $(a[i] * a[i]);
    58     for (int i = 0; i < n; i++) b2[i] = $(b[i] * b[i]);
    59     fft(a2, 1), fft(b2, 1);
    60     for (int i = 0; i < lim; i++) c[i] = c[i] - a2[i] * b2[i] * 2;
    61 
    62     for (int i = 0; i < lim; i++) a2[i] = b2[i] = $();
    63     for (int i = 0; i < m; i++) a2[i] = $(a[i]);
    64     for (int i = 0; i < n; i++) b2[i] = $(b[i] * b[i] * b[i]);
    65     fft(a2, 1), fft(b2, 1);
    66     for (int i = 0; i < lim; i++) c[i] = c[i] + a2[i] * b2[i];
    67 
    68     fft(c, -1);
    69     for (int i = m - 1; i < n; i++)
    70         if (fabs(c[i].x) < 0.5) q.push(i - m + 2);
    71     for (printf("%lu
    ", q.size()); !q.empty(); q.pop()) printf("%d ", q.front());
    72 }
  • 相关阅读:
    windows系统下强制杀死某个进程
    onenote快捷键
    sublime封装代码块快捷键、eemet插件安装、Loading PyV8 binary...的解决办法
    google浏览器截长图的方法
    (转)Java基础加强之并发(二)常用的多线程实现方式
    hibernate学习(初识)
    Spring中的事务操作
    JDBC最原始的代码做查询操作
    Spring的JDBC模板
    Spring AOP
  • 原文地址:https://www.cnblogs.com/zhangbuang/p/11068838.html
Copyright © 2011-2022 走看看