题目链接:P4173 残缺的字符串

题意

给定长度为 \(m\) 的模式串和长度为 \(n\) 的目标串,两个串都带有通配符,求所有匹配的位置。

思路

FFT

带有通配符的字符串匹配问题。

设模式串为 \(p\),目标串为 \(t\),将两个串的内容都根据字母先后顺序映射到 \(1\) 到 \(26\)。

如果不带有通配符,那么 \(t\) 以第 \(k\) 位结束的长度为 \(|p|\) 的子串与 \(p\) 匹配时有

\[\sum_{i=0}^{|p|-1} (p[i] - t[k - |p| + 1 + i])^2 = 0
\]

如果带有通配符,只需将上式稍微改一下就行。

让两个串中的所有通配符映射到 \(0\),设匹配结果为 \(f\),则有

\[f[i] = \sum_{i=0}^{|p|-1} (p[i] - t[k - |p| + 1 + i])^2 \cdot p[i] \cdot t[k - |p| + 1 + i]
\]

接下来翻转 \(p\) 串 (\(FFT\) 的套路),设 \(r[|p| - i - 1] = p[i]\),则有

\[f[i] = \sum_{i=0}^{|p|-1} (r[|p| - i - 1] - t[k - |p| + 1 + i])^2 \cdot r[|p| - i - 1] \cdot t[k - |p| + 1 + i]
\]

下标加起来等于 \(k\),令 \(j = |p| - i - 1\),则

\[f[i] = \sum_{i + j = k} (r[j] - t[i])^2 \cdot r[j] \cdot t[i]
\]

展开后有

\[f[i] = \sum_{i + j = k} (r[j]^3t[i] + t[i]^3r[j] - 2\cdot r[j]^2t[i]^2)
\]

用 \(FFT\) 分别求一下卷积即可。

代码

#include <bits/stdc++.h>
using namespace std;
const double PI = acos(-1);
const double eps = 1e-8;
typedef complex<double> Complex;
const int maxn = 2e6 + 10; Complex p[maxn], t[maxn];
Complex a[maxn], b[maxn], c[maxn], d[maxn];
Complex ans[maxn];
string str;
int m, n;
int bit = 2, rev[maxn]; void get_rev(){
memset(rev, 0, sizeof(rev));
while(bit <= n + m) bit <<= 1;
for(int i = 0; i < bit; ++i) {
rev[i] = (rev[i >> 1] >> 1) | (bit >> 1) * (i & 1);
}
} void FFT(Complex *a, int op) {
for(int i = 0; i < bit; ++i) {
if(i < rev[i]) swap(a[i], a[rev[i]]);
}
for(int mid = 1; mid < bit; mid <<= 1) {
Complex wn = Complex(cos(PI / mid), op * sin(PI / mid));
for(int j = 0; j < bit; j += mid<<1) {
Complex w(1, 0);
for(int k = 0; k < mid; ++k, w = w * wn) {
Complex x = a[j + k], y = w * a[j + k + mid];
a[j + k] = x + y, a[j + k + mid] = x - y;
}
}
}
} int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> m >> n;
cin >> str;
for(int i = 0; i < m; ++i) {
p[m - i - 1] = str[i] == '*' ? 0 : (str[i] - 'a' + 1);
}
cin >> str;
for(int i = 0; i < n; ++i) {
t[i] = str[i] == '*' ? 0 : (str[i] - 'a' + 1);
}
get_rev();
for(int i = 0; i < bit; ++i) {
a[i] = p[i] * p[i] * p[i];
b[i] = t[i];
}
FFT(a, 1); FFT(b, 1);
for(int i = 0; i < bit; ++i) {
ans[i] += a[i] * b[i];
} for(int i = 0; i < bit; ++i) {
a[i] = p[i];
b[i] = t[i] * t[i] * t[i];
}
FFT(a, 1); FFT(b, 1);
for(int i = 0; i < bit; ++i) {
ans[i] += a[i] * b[i];
} for(int i = 0; i < bit; ++i) {
a[i] = p[i] * p[i];
b[i] = t[i] * t[i];
}
FFT(a, 1); FFT(b, 1);
for(int i = 0; i < bit; ++i) {
ans[i] -= a[i] * b[i] * Complex(2, 0);
} FFT(ans, -1);
queue<int> q;
for(int i = m - 1; i < n; ++i) {
if((int)(ans[i].real() / bit + 0.5) == 0) q.push(i - m + 2);
}
cout << q.size() << endl;
while(q.size()) {
cout << q.front() << " ";
q.pop();
}
cout << endl;
return 0;
}

洛谷 P4173 残缺的字符串 (FFT)的更多相关文章

  1. 洛谷P4173 残缺的字符串(FFT)

    传送门 话说为什么字符串会和卷积扯上关系呢……到底得脑洞大到什么程度才能想到这种东西啊……大佬太珂怕了…… 因为通配符的关系,自动机已经废了 那么换种方式考虑,如果两个字符串每一位对应的编码都相等,那 ...

  2. 洛谷 P4173 残缺的字符串

    (不知道xjb KMP可不可以做的说) (假设下标都以0开头) 对于有一定偏移量的序列的 对应位置 匹配或者数值计算的题,这里是有一种套路的,就是把其中一个序列翻转过来,然后卷积一下,所得到的新序列C ...

  3. 洛谷P4173 残缺的字符串

    题目大意: 两个带通配符的字符串\(a,b\),求\(a\)在\(b\)中出现的位置 字符串长度\(\le 300000\) 考虑魔改一发\(kmp\),发现魔改不出来 于是考虑上网搜题解 然后考虑\ ...

  4. Luogu P4173 残缺的字符串-FFT在字符串匹配中的应用

    P4173 残缺的字符串 FFT在字符串匹配中的应用. 能解决大概这种问题: 给定长度为\(m\)的A串,长度为\(n\)的B串.问A串在B串中的匹配数 我们设一个函数(下标从\(0\)开始) \(C ...

  5. P4173 残缺的字符串(FFT字符串匹配)

    P4173 残缺的字符串(FFT字符串匹配) P4173 解题思路: 经典套路将模式串翻转,将*设为0,设以目标串的x位置匹配结束的匹配函数为\(P(x)=\sum^{m-1}_{i=0}[A(m-1 ...

  6. P4173 残缺的字符串 fft

    题意:给你两个字符串,问你第一个在第二个中出现过多少次,并输出位置,匹配时是模糊匹配*可和任意一个字符匹配 题解:fft加速字符串匹配; 假设上面的串是s,s长度为m,下面的串是p,p长度为n,先考虑 ...

  7. luoguP4173 残缺的字符串 FFT

    luoguP4173 残缺的字符串 FFT 链接 luogu 思路 和昨天做的题几乎一样. 匹配等价于(其实我更喜欢fft从0开始) \(\sum\limits_{i=0}^{m-1}(S[i+j]- ...

  8. BZOJ 4259: 残缺的字符串 [FFT]

    4259: 残缺的字符串 题意:s,t,星号任意字符,匹配方案数 和上题一样 多乘上一个\(a_{j+i}\)就行了 #include <iostream> #include <cs ...

  9. 洛谷.3803.[模板]多项式乘法(FFT)

    题目链接:洛谷.LOJ. FFT相关:快速傅里叶变换(FFT)详解.FFT总结.从多项式乘法到快速傅里叶变换. 5.4 又看了一遍,这个也不错. 2019.3.7 叕看了一遍,推荐这个. #inclu ...

随机推荐

  1. 使用java读取excel数据

    package excelOperation2; import java.io.File; import java.io.FileNotFoundException; import java.util ...

  2. Linux命令之解压

    Linux命令之解压 使用tar命令解压.zip文件的时候,遇到如下异常, tar -xzvf guangwang.zip gzip: stdin has more than one entry--r ...

  3. 深入解读 Redis 的持久化

    Redis持久化 Java大猿帅成长手册,GitHub JavaEgg ,N线互联网开发必备技能兵器谱 Redis 的数据全部在内存里,如果突然宕机,数据就会全部丢失,因此必须有一种机制来保证 Red ...

  4. python学习笔记:模块——os模块(操作文件/目录)

    import os os.rename(old,new) #重命名文件或目录 os.remove(f)#删除文件 os.mkdir('china/beijing') #创建文件夹 os.makedir ...

  5. TP5.1/TP框架的访问控制,访问不存在的模块、控制器、方法等控制

    TP框架的访问控制,默认模块.控制器.方法等 在tp框架中,config文件夹下的app.php文件可以设置默认的空模块名,默认的空控制器名. 举例:以上项目中有admin.common.api.er ...

  6. MySQL数据库学习初步

    我使用的环境是Win7,开始学习PHP和MySQL,并且买了本<Head First PHP & MySQL>,可以从Head First Labs官网获得HeadFirst系列书 ...

  7. Java7任务并行执行神器:Fork&Join框架

    Fork/Join是什么? Fork/Join框架是Java7提供的并行执行任务框架,思想是将大任务分解成小任务,然后小任务又可以继续分解,然后每个小任务分别计算出结果再合并起来,最后将汇总的结果作为 ...

  8. 关于JS递归函数求斐波那契数列两种实现方法

    百度已经解释的很详细了,但是不写注释还真是看不懂,递归,就直接套公式了,for循坏,我们就用EXCEL看一下规律 可以看到B是A+B的和,A往后就是B的值,所以我们需要第三个变量来保存他们的和,取出B ...

  9. MVC中的自定义标签分页控件,仅供大家学习!!

    public static HtmlString ShowPageNavigate(this HtmlHelper htmlHelper, int currentPage, int pageSize, ...

  10. 【外】001-python3之zip函数

    zip函数语法格式zip(可迭代对象1, 可迭代对象2, ... ,可迭代对象n) 函数接收任意个可迭代对象作为参数, 将所有对象中对应位置上的元素分别打包在一起组成一个tuple, 并将所有的tup ...