P4173 残缺的字符串

FFT在字符串匹配中的应用.

能解决大概这种问题:

给定长度为\(m\)的A串,长度为\(n\)的B串。问A串在B串中的匹配数

我们设一个函数(下标从\(0\)开始)

\(C(x,y) =A(x)- B(y)\),若为0,表示B串中以第\(y\)个字符结尾的字符可以与A串中以\(x\)节为结尾的字符可以匹配

\(P(x) = \sum_{i = 0}^{m - 1}C(i,x - m + i + 1)\)

但是很遗憾当\(P(x)\),等于零时,只能够说明上述子串的字符集相同.

为什么?因为负数的存在!

我们考虑怎么去掉负数,平方!

\(P(x) = \sum_{i = 0}^{m - 1}(A(i) - B[x - m + i + 1])^2\)

这时候,如果上式为\(0\),就能证明B串中\(x\)结尾的串可以与A匹配.

老样子设

\(f(i) = A(m - i - 1)\)

\(g(i) = B(i)\)

则有

\(P(x) = \sum_{i = 0}^{m - 1}f(m - i - 1)^2 -\sum_{i = 0}^{m - 1}2f(m - i - 1)g(x - m + i + 1) -\sum_{i = 0}^{m - 1}g(x - m + i + 1)^2\)

发现第一项和第三项是可以通过处理前缀和搞出来的!

而第二项是个卷积,我们只需要求\(P(x)\)是否为零就好了。

我们终于这到了题目上.

这道题目中含有通配符,上式很明显不再成立

但大体思路还是不变的

\(C(x)\)与\(P(x)\)的意义不变

我们设

\(P(x) = \sum_{i = 0}^{m - 1}(A(i) - B(x - m + i + 1))^2A(i)B(x - m + i + 1)\)

即当B串\(x\)的位置为通配符时,\(B(x) = 0\),A同理

这样我们就又能用\(P(x)\)表示能否匹配了

同理,设\(f(x)\)与\(g(x)\)意义同上

\(P(x) =\sum_{i = 0}^{m - 1}f(m - i - 1)^3g(x - m + i + 1) - \sum_{i = 0}^{m - 1}f(m - i - 1)^2g(x - m + i + 1)+\sum_{i = 0}^{m - 1}f(m - i - 1)g(x - m + i + 1)^3\)

然后发现

上式三项都是卷积!

所以我们跑7遍FFT就好了

#include<cstdio>
#include<iostream>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
const int N = 3e5 + 3;
const double Pi = acos(-1.0);
const double eps = 1e-12;
struct point{
double x,y;
point(double xx = 0,long double yy = 0){
x = xx,y = yy;
}
}a[N << 2],b[N << 2],c[N << 2];
char s1[N],s2[N];
int c1[N],c2[N];
int r[N << 2];
int n,m,limit = 1,l;
vector <int> G;
point operator + (point a,point b){return point(a.x + b.x,a.y + b.y);}
point operator - (point a,point b){return point(a.x - b.x,a.y - b.y);}
point operator * (point a,point b){return point(a.x * b.x - a.y * b.y,a.x * b.y + a.y * b.x);}
inline void fftle(point *A,int type){
for(int i = 0;i < limit;++i)
if(i < r[i]) swap(A[i],A[r[i]]);
for(int mid = 1;mid < limit;mid <<= 1){
point Wn = point(cos(Pi / mid),type * sin(Pi / mid));
for(int R = mid << 1,j = 0;j < limit;j += R){
point w(1,0);
for(int k = 0;k < mid;++k,w = w * Wn){
point x = A[j + k],y = A[j + mid + k] * w;
A[j + k] = x + y;
A[j + mid + k] = x - y;
}
}
}
if(type == -1) for(int i = 0;i < limit;++i) A[i].x = A[i].x / limit;
}
int main(){
scanf("%d%d",&m,&n);
scanf("%s%s",s1,s2);
point zero = point(0,0);
for(int i = 0;i < m;++i) c1[i] = s1[m - i - 1] == '*' ? 0 : s1[m - i - 1] - 'a' + 1;
for(int i = 0;i < n;++i) c2[i] = s2[i] == '*' ? 0 : s2[i] - 'a' + 1;
while(limit <= (n + m)) limit <<= 1,l++;
for(int i = 0;i < limit;++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
for(int i = 0;i < m;++i) a[i].x = c1[i] * c1[i] * c1[i];
for(int i = 0;i < n;++i) b[i].x = c2[i];
fftle(a,1);fftle(b,1);
for(int i = 0;i < limit;++i) c[i] = c[i] + (a[i] * b[i]),a[i] = b[i] = zero;
for(int i = 0;i < m;++i) a[i].x = c1[i] * c1[i];
for(int i = 0;i < n;++i) b[i].x = c2[i] * c2[i];
fftle(a,1);fftle(b,1);
point w(2,0);
for(int i = 0;i < limit;++i) c[i] = c[i] - ((a[i] * b[i]) * w),a[i] = b[i] = zero;
for(int i = 0;i < m;++i) a[i].x = c1[i];
for(int i = 0;i < n;++i) b[i].x = c2[i] * c2[i] * c2[i];
fftle(a,1);fftle(b,1);
for(int i = 0;i < limit;++i) c[i] = c[i] + (a[i] * b[i]);
fftle(c,-1);
//for(int i = m - 1;i < n;++i) printf("%lf ",fabs(c[i].x / limit));puts("");
for(int i = m - 1;i < n;++i) if((fabs)(c[i].x) < 0.5) G.push_back(i + 2 - m);
printf("%d\n",(int)G.size());
for(int i = 0;i < (int)G.size();++i) printf("%d ",G[i]);
}

参考博客

Luogu P4173 残缺的字符串-FFT在字符串匹配中的应用的更多相关文章

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

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

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

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

  3. P4173 残缺的字符串 fft

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

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

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

  5. luogu P4173 残缺的字符串

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

  6. luoguP4173 残缺的字符串 FFT

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

  7. P4173 残缺的字符串

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

  8. leetcode笔记 动态规划在字符串匹配中的应用

    目录 leetcode笔记 动态规划在字符串匹配中的应用 0 参考文献 1. [10. Regular Expression Matching] 1.1 题目 1.2 思路 && 解题 ...

  9. BZOJ4259:残缺的字符串(FFT与字符串匹配)

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

随机推荐

  1. java方法重写规则 重载

    方法的重写规则 参数列表必须完全与被重写方法的相同: 返回类型必须完全与被重写方法的返回类型相同: 访问权限不能比父类中被重写的方法的访问权限更低.例如:如果父类的一个方法被声明为public,那么在 ...

  2. HTML 5适合小公司,适合在大平台上做内容

    Web App,现在有时候也称为轻应用,不仅是通过浏览器就能打开的应用.现在随着 HTML 5 在手机端的优越性,已经慢慢称为了 Web App 的主流.Web App 除了出现在 PC 的浏览器中, ...

  3. python 别名

  4. 【New Feature】阿里云快照服务技术解析

    一.背景   目前上云已经成为行业发展趋势,越来越多的企业级客户将业务系统和数据库迁移到云上.而传统的备份一体机/备份软件方式,并不适合云上ECS.RDS等产品的备份与容灾服务.阿里云块存储服务提供云 ...

  5. SaaS加速器II 能力中心:互利互补 共享商业红利

    摘要: 通过丰富的阿里集团和三方的业务能力API,缩短业务从0-1构建的周期和降低成本,我们希望能够把阿里巴巴在电商.金融.物流.高德以及其他领域沉淀出来商业最佳实践.商业能力,通过阿里云的渠道输出, ...

  6. 3DSMAX安装失败怎样卸载重新安装3DSMAX,解决3DSMAX安装失败的方法总结

    技术帖:3DSMAX没有按照正确方式卸载,导致3DSMAX安装失败.楼主也查过网上关于如何解决3DSMAX安装失败的一些文章,是说删除几个3DSMAX文件和3DSMAX软件注册表就可以解决3DSMAX ...

  7. SharpDX初学者教程第1部分:在Visual Studio 2013中设置SharpDX项目

    原文 http://www.johanfalk.eu/blog/sharpdx-tutorial-part-1-setting-up-a-sharpdx-project-in-visual-studi ...

  8. Python基础:07迭代器

    迭代器是在版本 2.2 被加入Python 的,它为类序列对象提供了一个类序列的接口.Python 的迭代无缝地支持序列对象,而且它还允许迭代非序列类型,包括用户定义的对象.它的出现,对列表迭代.字典 ...

  9. C#面向对象基础--类与对象

    1.类与对象 类是面向对象编程的基本单元:类造出来的变量叫对象. 一个类包含俩种成员:字段与方法. 字段即变量,方法即函数. 面向对象思想:教给我们如何合理的运用类的规则去编写代码. 2.类的字段 字 ...

  10. Hessian轻量级二进制远程调用框架

    Hessian轻量级二进制远程调用框架 Hessian是一个轻量级的二进制远程调用框架,官方文档地址,它主要包括Hessian远程调用协议.Hessian序列化协议以及客户端服务端代理等几部分,关于H ...