洛谷 P4173 残缺的字符串 (FFT)
题目链接:P4173 残缺的字符串
题意
给定长度为 \(m\) 的模式串和长度为 \(n\) 的目标串,两个串都带有通配符,求所有匹配的位置。
思路
FFT
带有通配符的字符串匹配问题。
设模式串为 \(p\),目标串为 \(t\),将两个串的内容都根据字母先后顺序映射到 \(1\) 到 \(26\)。
如果不带有通配符,那么 \(t\) 以第 \(k\) 位结束的长度为 \(|p|\) 的子串与 \(p\) 匹配时有
\]
如果带有通配符,只需将上式稍微改一下就行。
让两个串中的所有通配符映射到 \(0\),设匹配结果为 \(f\),则有
\]
接下来翻转 \(p\) 串 (\(FFT\) 的套路),设 \(r[|p| - i - 1] = p[i]\),则有
\]
下标加起来等于 \(k\),令 \(j = |p| - i - 1\),则
\]
展开后有
\]
用 \(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)的更多相关文章
- 洛谷P4173 残缺的字符串(FFT)
传送门 话说为什么字符串会和卷积扯上关系呢……到底得脑洞大到什么程度才能想到这种东西啊……大佬太珂怕了…… 因为通配符的关系,自动机已经废了 那么换种方式考虑,如果两个字符串每一位对应的编码都相等,那 ...
- 洛谷 P4173 残缺的字符串
(不知道xjb KMP可不可以做的说) (假设下标都以0开头) 对于有一定偏移量的序列的 对应位置 匹配或者数值计算的题,这里是有一种套路的,就是把其中一个序列翻转过来,然后卷积一下,所得到的新序列C ...
- 洛谷P4173 残缺的字符串
题目大意: 两个带通配符的字符串\(a,b\),求\(a\)在\(b\)中出现的位置 字符串长度\(\le 300000\) 考虑魔改一发\(kmp\),发现魔改不出来 于是考虑上网搜题解 然后考虑\ ...
- Luogu P4173 残缺的字符串-FFT在字符串匹配中的应用
P4173 残缺的字符串 FFT在字符串匹配中的应用. 能解决大概这种问题: 给定长度为\(m\)的A串,长度为\(n\)的B串.问A串在B串中的匹配数 我们设一个函数(下标从\(0\)开始) \(C ...
- P4173 残缺的字符串(FFT字符串匹配)
P4173 残缺的字符串(FFT字符串匹配) P4173 解题思路: 经典套路将模式串翻转,将*设为0,设以目标串的x位置匹配结束的匹配函数为\(P(x)=\sum^{m-1}_{i=0}[A(m-1 ...
- P4173 残缺的字符串 fft
题意:给你两个字符串,问你第一个在第二个中出现过多少次,并输出位置,匹配时是模糊匹配*可和任意一个字符匹配 题解:fft加速字符串匹配; 假设上面的串是s,s长度为m,下面的串是p,p长度为n,先考虑 ...
- luoguP4173 残缺的字符串 FFT
luoguP4173 残缺的字符串 FFT 链接 luogu 思路 和昨天做的题几乎一样. 匹配等价于(其实我更喜欢fft从0开始) \(\sum\limits_{i=0}^{m-1}(S[i+j]- ...
- BZOJ 4259: 残缺的字符串 [FFT]
4259: 残缺的字符串 题意:s,t,星号任意字符,匹配方案数 和上题一样 多乘上一个\(a_{j+i}\)就行了 #include <iostream> #include <cs ...
- 洛谷.3803.[模板]多项式乘法(FFT)
题目链接:洛谷.LOJ. FFT相关:快速傅里叶变换(FFT)详解.FFT总结.从多项式乘法到快速傅里叶变换. 5.4 又看了一遍,这个也不错. 2019.3.7 叕看了一遍,推荐这个. #inclu ...
随机推荐
- Python进阶:set和dict/对象引用、可变性和垃圾回收/元类编程/迭代器和生成器
frozenset:不可变集合,无序,不重复 dict上的特性: 1. dict的key或者set的值 都必须是可以hash的(不可变对象 都是可hash的, str, fronzenset, tup ...
- MYSQL的SQL_CALC_FOUND_ROWS 和count(*)
mysql的SQL_CALC_FOUND_ROWS 和 count(*) 在很多分页的程序中都这样写: SELECT COUNT(*) from `table` WHERE ......; 查出符合 ...
- Android 测试点归纳总结
前言 除了测试平台工具,业务测试的总结和思考同样重要,这里总结了一些Android测试知识点,可以辅助业务测试快速形成测试用例和检查点,当作抛砖引玉分享给大家.如有思考不全面的地方,欢迎大家指出来. ...
- git使用记录一:配置账户信息
配置的级别 git config --gloabal 针对当前用户下所有的项目 设置 git config --local 针对当前工作区的项目来进行设置 git config --system 针对 ...
- QTP - excel操作
1. 以数据库的形式访问Excel 通常,我们与Excel的交互,是通过创建Excel对象的方式: Set ExcelApp = CreateObject("Excel.Applicatio ...
- PHP CURL 模拟form表单上传遇到的小坑
1:引用的时候 $parans ['img']=new \CURLFile($param); 传入的文件 在PHP版本5.5以上记得new CURLFile 不然会上传不成功 /** * http p ...
- Tomcat启动脚本(1)startup.bat
@echo off rem Licensed to the Apache Software Foundation (ASF) under one or more rem contributor lic ...
- tdom中selectNodes的使用
tdom中selectNodes的使用 */--> pre.src {background-color: #002b36; color: #839496;} pre.src {backgroun ...
- shell脚本 set命令
- bash命令根据历史记录补全
用zsh比较方便的一个功能是在找之前用过的命令时可以先输入一部分命令作为过滤条件, 比如,想找 docker run 开头的历史命令,只需要键入 docker run 然后按 ↑ 进行选择. 但是在用 ...