\(\text{Problem}\)

大概就是带通配符的字符串匹配问题,输出所有比配位置

\(1\le n \le 3\times 10^5\)

\(\text{Solution}\)

这是 \(FFT\) 在字符串匹配中的应用

默认下标以 \(0\) 开始,记通配符数值为 \(0\)

\(A\) 为文本串,考虑 \(A\) 从某一位 \(i\) 开始与 \(B\) 的匹配结果

构造一个函数描述这个结果 \(F_i = \sum_{j=0}^{m-1} (A_{i+j}-B_j)^2 A_{i+j} B_j\)

\(F_i = 0\) 则 \(i\) 这个开始匹配位是成功的

我们要计算每个 \(F_i\),这还是不高效

但考虑把 \(B\) 翻转,\(F_i = \sum_{j=0}^{m-1} (A_{i+j}-B_{m-j-1})^2 A_{i+j} B_{m-j-1}\)

发现 \(A,B\) 小标加起来恒为 \(i+m-1\) !

这是多项式卷积的形式!

那我们就考虑把 \(A,B\) 当做一个多项式,\(F(x)=A(x)B(x)\)

这里的 \(F(x)\) 第 \(i+m-1\) 项的系数就是原来 \(F_i\) 的结果

这样就可以 \(O(n \log n)\) 做匹配了

\(\text{Code}\)

#include <cstdio>
#include <iostream>
#include <algorithm>
#define IN inline
#define RE register
using namespace std;
typedef long long LL; const int N = 1e6 + 1e5, P = 998244353, g = 3;
int n, m, A[N], B[N], rev[N];
LL a[N], b[N], F[N];
char s[N]; IN int fpow(LL x, int y){LL s = 1; for(; y; y >>= 1, x = x * x % P) if (y & 1) s = s * x % P; return s;}
IN void NTT(LL *a, int lim, int inv)
{
if (lim == 1) return;
for(RE int i = 0; i < lim; i++) if (i < rev[i]) swap(a[i], a[rev[i]]);
for(RE int mid = 1; mid < lim; mid <<= 1)
{
int I = fpow(g, (P - 1) / (mid << 1));
if (inv == -1) I = fpow(I, P - 2);
for(RE int i = 0; i < lim; i += (mid << 1))
{
LL W = 1;
for(RE int j = 0, x, y; j < mid; j++, W = W * I % P)
x = a[i + j], y = W * a[i + j + mid] % P,
a[i + j] = (x + y) % P, a[i + j + mid] = (x - y + P) % P;
}
}
} int main()
{
scanf("%d%d%s", &m, &n, s);
for(RE int i = 0; i < m; i++) if (s[i] == '*') A[i] = 0; else A[i] = s[i] - 'a' + 1;
scanf("%s", s);
for(RE int i = 0; i < n; i++) if (s[i] == '*') B[i] = 0; else B[i] = s[i] - 'a' + 1;
int lim = 1; while (lim < n + m - 1) lim <<= 1;
int bit = 0; while ((1 << bit) < lim) ++bit;
for(RE int i = 0; i < lim; i++) rev[i] = (rev[i>>1]>>1) | ((i&1)<<(bit-1));
reverse(A, A + m); for(RE int i = 0; i < lim; i++) a[i] = A[i] * A[i] * A[i], b[i] = B[i];
NTT(a, lim, 1), NTT(b, lim, 1);
for(RE int i = 0; i < lim; i++) F[i] = a[i] * b[i] % P; for(RE int i = 0; i < lim; i++) b[i] = B[i] * B[i] * B[i], a[i] = A[i];
NTT(a, lim, 1), NTT(b, lim, 1);
for(RE int i = 0; i < lim; i++) F[i] = (F[i] + a[i] * b[i] % P) % P; for(RE int i = 0; i < lim; i++) a[i] = A[i] * A[i], b[i] = B[i] * B[i] % P;
NTT(a, lim, 1), NTT(b, lim, 1);
for(RE int i = 0; i < lim; i++) F[i] = (F[i] - a[i] * b[i] * 2 % P + P) % P;
NTT(F, lim, -1); int inv = fpow(lim, P - 2);
for(RE int i = 0; i < lim; i++) F[i] = F[i] * inv % P; int ans = 0;
for(RE int i = m - 1; i < n; i++) if (!F[i]) ++ans;
printf("%d\n", ans);
for(RE int i = m - 1; i < n; i++) if (!F[i]) printf("%d ", i - m + 2);
}

LG P4173 残缺的字符串的更多相关文章

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

    题目链接:P4173 残缺的字符串 题意 给定长度为 \(m\) 的模式串和长度为 \(n\) 的目标串,两个串都带有通配符,求所有匹配的位置. 思路 FFT 带有通配符的字符串匹配问题. 设模式串为 ...

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

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

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

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

  4. P4173 残缺的字符串 fft

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

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

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

  6. 洛谷P4173 残缺的字符串

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

  7. [Luogu P4173]残缺的字符串 ( 数论 FFT)

    题面 传送门:洛咕 Solution 这题我写得脑壳疼,我好菜啊 好吧,我们来说正题. 这题.....emmmmmmm 显然KMP类的字符串神仙算法在这里没法用了. 那咋搞啊(或者说这题和数学有半毛钱 ...

  8. luogu P4173 残缺的字符串

    传送门 两种做法,一种是依次考虑每种字符,然后如果某个位置是该字符或者是\(*\)对应的值就是1,否则是0,然后把第一个串倒过来,fft卷积起来,最后看对应位置的值是否为m 然而上面那个做法在字符集大 ...

  9. P4173 残缺的字符串

    题目链接 题意分析 啥 ? ? ? \(FFT\)做字符串匹配 可是就是这样 我们定义匹配函数 我们定义\(A\)是匹配串 \(B\)是被匹配串 我们当前到达\(B\)串的\(x\)位置 \[P(x) ...

  10. 洛谷 P4173 残缺的字符串

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

随机推荐

  1. 研究光度立体法阶段性小结和优化(可20ms获取4个2500*2000灰度图的Normal Map)。

    这个东西是我接触的第一个非2D方面的算法,到目前为止其实也没有完全搞定,不过可能短时间内也无法突破.先把能搞定的搞定吧. 这个东西也有一大堆参考资料,不过呢,搜来搜去其实也就那些同样的东西,个人觉得就 ...

  2. Duplicate property mapping of xxx found in xx 嵌套异常,重复的属性在映射中发现。

    该异常的原意是因为在映射文件中出现了两个一样的属性名: <property name="相同的属性名出现了两次以上" > <property name=" ...

  3. 【数据库】PostgreSQL/PgSql-根据模式名和字段名查询有该字段的所有表信息【通过表元数据信息和函数实现】

    一.利用表数据信息查询表和字段信息 (一)从pg_tables中查询表信息 select tablename from pg_tables where schemaname='ap' and tabl ...

  4. java中使用apache poi 读取 doc,docx,ppt,pptx,xls,xlsx,txt,csv格式的文件示例代码

    java使用apache poi 读取 doc,docx,ppt,pptx,xls,xlsx,txt,csv格式的文件示例代码 1.maven依赖添加 在 pom 文件中添加如下依赖 <depe ...

  5. Django框架:2、静态文件配置、form表单、request对象、pycharm链接数据库、django链接数据库、ORM框架

    Django框架 目录 Django框架 一.静态文件配置 1.静态文件 2.配置方法 二.form表单 1.action属性 2.method属性 三.request对象 1.基本用法 四.pych ...

  6. 小程序与app区别及测试点

    小程序和app区别 1. 用户获取渠道区别 小程序: 二维码.用户分享推荐.搜索小程序 APP: 需要去应用市场(或其他)下载 2. 下载.安装卸载 小程序: 不需下载安装,清除时直接删除小程序 AP ...

  7. JavaScript:如何知道一个变量的数据类型?:typeof

    使用typeof去查看一个变量的数据类型,如下图所示,展示了JS的七大基础数据类型和对象: 这里有必要提一下: 函数也是一个对象,但是函数的特殊性,使得在使用typeof去判断其类型的时候,会输出fu ...

  8. mybatis 之定义拦截器 控制台SQL的打印

    类型 先说明Mybatis中可以被拦截的类型具体有以下四种: 1.Executor:拦截执行器的方法.2.ParameterHandler:拦截参数的处理.3.ResultHandler:拦截结果集的 ...

  9. 论文解读(CAN)《Contrastive Adaptation Network for Unsupervised Domain Adaptation》

    论文信息 论文标题:Contrastive Adaptation Network for Unsupervised Domain Adaptation论文作者:Guoliang Kang, Lu Ji ...

  10. Java读取文件后文件被占用

    Java读取文件响应后文件一直被占用问题 原因: 由于是封装的函数,请求和响应对象都是 形参地址 虽然在此函数里关闭了输出流,但是由于有返回值,调用未结束,输出流无法提前关闭 解决: 1:调用函数后, ...