题意:

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

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

数据范围:n,m<=3e5

解法:

先介绍FFT进行字符串匹配的原理:

假设A和B是数字,那么A=B可以等价为A-B=0,

当A和B是字符串的时候,A=B似乎可以变为:∑i=0n−1(A[i]−b[i])=0\sum_{i=0}^{n-1}(A[i]-b[i])=0∑i=0n−1​(A[i]−b[i])=0

但是求和存在正负相消,因此将每个位置的计算变成绝对值:∑i=0n−1∣A[i]−B[i]∣=0\sum_{i=0}^{n-1}|A[i]-B[i]|=0∑i=0n−1​∣A[i]−B[i]∣=0

绝对值不好算,可以平方一下把式子变成:∑i=0n−1(A[i]−B[i])2=0\sum_{i=0}^{n-1}(A[i]-B[i])^2=0∑i=0n−1​(A[i]−B[i])2=0

展开变为:∑i=0n−1(A[i]2+B[i]2)−2∑i=0n−1A[i]∗B[i]=0\sum_{i=0}^{n-1}(A[i]^2+B[i]^2)-2\sum_{i=0}^{n-1}A[i]*B[i]=0∑i=0n−1​(A[i]2+B[i]2)−2∑i=0n−1​A[i]∗B[i]=0

左边的式子可以预处理前缀和算,

右边的式子可以通过将B串翻转为B’,变为:2∑i=0n−1A[i]∗B′[n−1−i]2\sum_{i=0}^{n-1}A[i]*B'[n-1-i]2∑i=0n−1​A[i]∗B′[n−1−i]

是卷积形式,可以用FFT计算,复杂度O(nlogn)O(nlogn)O(nlogn)

-----分割线-----

观察复杂度,显然用KMP算法匹配效率更高,那用FFT匹配有啥用呢?

当字符串中存在通配符时,KMP算法没办法进行匹配,这时候就得用FFT了。

对于A[i]和B[i],如果他们能匹配,那么一定满足下列条件之一:

1.A[i]是通配符

2.B[i]是通配符

3.A[i]=B[i]

我们原本要满足的是(A[i]−B[i])2=0(A[i]-B[i])^2=0(A[i]−B[i])2=0,即条件三,

现在多了通配符的条件,可以设通配符为0,

那么只需要把式子变为(A[i]−B[i])2∗A[i]∗B[i]=0(A[i]-B[i])^2*A[i]*B[i]=0(A[i]−B[i])2∗A[i]∗B[i]=0即可,

用0乘任何数都等于0巧妙的将三个条件逻辑与了起来。

那么串A=串B的式子就变为:∑i=0n−1(A[i]−B[i])2∗A[i]∗B[i]\sum_{i=0}^{n-1}(A[i]-B[i])^2*A[i]*B[i]∑i=0n−1​(A[i]−B[i])2∗A[i]∗B[i]

将式子展开变为:∑i=0n−1(A[i]3∗B[i])−2∑i=0n−1(A[i]2∗B[i]2)+∑i=0n−1(A[i]∗B[i]3)\sum_{i=0}^{n-1}(A[i]^3*B[i])-2\sum_{i=0}^{n-1}(A[i]^2*B[i]^2)+\sum_{i=0}^{n-1}(A[i]*B[i]^3)∑i=0n−1​(A[i]3∗B[i])−2∑i=0n−1​(A[i]2∗B[i]2)+∑i=0n−1​(A[i]∗B[i]3)

翻转B串变为:∑i=0n−1(A[i]3∗B′[n−1−i])−2∑i=0n−1(A[i]2∗B′[n−1−i]2)+∑i=0n−1(A[i]∗B′[n−1−i]3)\sum_{i=0}^{n-1}(A[i]^3*B'[n-1-i])-2\sum_{i=0}^{n-1}(A[i]^2*B'[n-1-i]^2)+\sum_{i=0}^{n-1}(A[i]*B'[n-1-i]^3)∑i=0n−1​(A[i]3∗B′[n−1−i])−2∑i=0n−1​(A[i]2∗B′[n−1−i]2)+∑i=0n−1​(A[i]∗B′[n−1−i]3)

令C(n)=∑i=0n(A[i]3∗B′[n−i])−2∑i=0n(A[i]2∗B′[n−i]2)+∑i=0n(A[i]∗B′[n−i]3)C(n)=\sum_{i=0}^{n}(A[i]^3*B'[n-i])-2\sum_{i=0}^{n}(A[i]^2*B'[n-i]^2)+\sum_{i=0}^{n}(A[i]*B'[n-i]^3)C(n)=∑i=0n​(A[i]3∗B′[n−i])−2∑i=0n​(A[i]2∗B′[n−i]2)+∑i=0n​(A[i]∗B′[n−i]3)

FFT计算出C[],然后逐个判断C[i]是否为0即可。

要用eps判断,因为是浮点数。

-----分割线-----

一开始没想懂为什么只需要判断C(i)是否为0,c(i-m)不用管,手玩了一组数据就懂了:


翻转,空余处补零,卷积的时候前面部分会和0消掉,所以直接判断C(i)就行了。

-----分割线-----

学自:https://www.luogu.com.cn/blog/cqbzllsw/bzoj-4259-can-que-di-zi-fu-chuan

code:

#include<bits/stdc++.h>
using namespace std;
const double P=acos(-1.0);
struct CC{//复数double x,y;CC(double xx=0,double yy=0){x=xx,y=yy;}CC operator+(const CC &a)const{return CC(x+a.x,y+a.y);}CC operator-(const CC &a)const{return CC(x-a.x,y-a.y);}CC operator*(const CC &a)const{return CC(x*a.x-y*a.y,x*a.y+y*a.x);}CC operator*(const double a)const{return CC(x*a,y*a);}
};
void change(CC y[],int len){for(int i=1,j=len/2;i<len-1;i++){if(i<j)swap(y[i],y[j]);int k=len/2;while(j>=k){j-=k;k/=2;}if(j<k)j+=k;}
}
void fft(CC y[],int len,int on){//on为1或者-1,-1的时候表示逆变换change(y,len);for(int h=2;h<=len;h<<=1){CC wn(cos(-on*2*P/h),sin(-on*2*P/h));for(int j=0;j<len;j+=h){CC w(1,0);for(int k=j;k<j+h/2;k++){CC u=y[k];CC t=w*y[k+h/2];y[k]=u+t;y[k+h/2]=u-t;w=w*wn;}}}if(on==-1){for(int i=0;i<len;i++){y[i].x/=len;}}
}
//
const int maxm=2e6+5;
char s[maxm];
char t[maxm];
int a[maxm];
int b[maxm];
CC A[maxm];
CC B[maxm];
CC C[maxm];
int n,m;
signed main(){scanf("%d%d",&m,&n);scanf("%s%s",t,s);for(int i=0;i<n;i++)a[i]=(s[i]=='*'?0:s[i]-'a'+1);for(int i=0;i<m;i++)b[i]=(t[i]=='*'?0:t[i]-'a'+1);reverse(b,b+m);//int len=1;while(len<n*2)len<<=1;//for(int i=0;i<n;i++)A[i]=CC(a[i]*a[i]*a[i],0);for(int i=n;i<len;i++)A[i]=CC(0,0);for(int i=0;i<m;i++)B[i]=CC(b[i],0);for(int i=m;i<len;i++)B[i]=CC(0,0);fft(A,len,1);fft(B,len,1);for(int i=0;i<len;i++)C[i]=C[i]+A[i]*B[i];//for(int i=0;i<n;i++)A[i]=CC(a[i]*a[i],0);for(int i=n;i<len;i++)A[i]=CC(0,0);for(int i=0;i<m;i++)B[i]=CC(b[i]*b[i],0);for(int i=m;i<len;i++)B[i]=CC(0,0);fft(A,len,1);fft(B,len,1);for(int i=0;i<len;i++)C[i]=C[i]-A[i]*B[i]*2.0;//for(int i=0;i<n;i++)A[i]=CC(a[i],0);for(int i=n;i<len;i++)A[i]=CC(0,0);for(int i=0;i<m;i++)B[i]=CC(b[i]*b[i]*b[i],0);for(int i=m;i<len;i++)B[i]=CC(0,0);fft(A,len,1);fft(B,len,1);for(int i=0;i<len;i++)C[i]=C[i]+A[i]*B[i];//fft(C,len,-1);vector<int>ans;for(int i=m-1;i<n;i++){if(fabs(C[i].x)<0.5){ans.push_back(i-m+2);}}printf("%d\n",ans.size());for(auto i:ans){printf("%d ",i);}return 0;
}

P4173 残缺的字符串(带通配符的字符串匹配,FFT)相关推荐

  1. 字符串转换成整数,带通配符的字符串匹配

    之前本一直想写写神经网络算法和EM算法,但写这两个算法实在需要大段大段的时间,而平时上班,周末则跑去北大教室自习看书(顺便以时间为序,说下过去半年看过的自觉还不错的数学史方面的书:<数理统计学简 ...

  2. python带通配符的字符串匹配_Bash技巧:实例介绍数个参数扩展表达式以处理字符串变量...

    Linux 的 bash shell 提供了多种形式的参数扩展表达式,可以获取变量自身的值,或者对变量值进行特定处理得到一个新的值,等等. 本篇文章对字符串变量值相关的参数扩展表达式进行汇总说明. 假 ...

  3. 字符串转换成整数,通配符的字符串匹配问题

    http://blog.csdn.net/v_july_v/article/details/9024123#comments 前言 之前本一直想写写神经网络算法和EM算法,但写这两个算法实在需要大段大 ...

  4. P4173 残缺的字符串 FFT匹配含有通配符的字符串

    传送门 文章目录 题意: 思路: 题意: 给你两个长度为m,nm,nm,n的串a,ba,ba,b,问你bbb串中每个长度为mmm的连续字串能否与aaa完全匹配,其中含有通配符∗*∗,输出每个位置的开头 ...

  5. 洛谷 - P4173 残缺的字符串(多项式匹配字符串-NTT)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的字符串 sss 和一个长度为 mmm 的字符串 ttt,都含有通配符 '*',现在问字符串 ttt 可以匹配字符串 nnn 的哪些位置 题目分析 ...

  6. P4173 残缺的字符串

    P4173 残缺的字符串 题意: 有A,B两个串,每个串都有通配符,问A为模板串,对于 B 的每一个位置 i,从这个位置开始连续 m 个字符形成的子串是否可能与 A 串完全匹配? 题解: 我们定义两个 ...

  7. c int转字符串_【C++实现python字符串函数库】字符串匹配函数startswith与endswith

    [C++实现python字符串函数库]字符串匹配函数startswith与endswith 这两个函数用于匹配字符串的开头或末尾,判断是否包含另一个字符串,它们返回bool值.startswith() ...

  8. 通配符?子字符串匹配主字符串次数_leetcode 44 通配符匹配(c++)

    ### 题目 给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配. '?' 可以匹配任何单个字符. '*' 可以匹配任意字符串(包括空字符串). 两个字符 ...

  9. 通配符?子字符串匹配主字符串次数_突破LeetCode,拿BAT大厂offer之《正则表达式匹配》(动态规划)...

    导读:算法哥前面分享了一个<通配符匹配>,有粉丝留言,算法哥你再讲讲leetcode上另一道<正则表达式匹配>,正则表达式匹配这道题是前面通配符匹配的加强版,大家一起来学习吧! ...

  10. java中字符串的精确匹配_Java最佳实践–字符串性能和精确字符串匹配

    java中字符串的精确匹配 在使用Java编程语言时,我们将继续讨论与建议的实践有关的系列文章,我们将讨论String性能调优. 我们将专注于如何有效地处理字符串创建, 字符串更改和字符串匹配操作. ...

最新文章

  1. 翻译:CREATE DATABASE语句
  2. ffmpeg库编译加文字_使用ffmpeg库编译错误及解决办法
  3. Java HashMap的实现原理详解
  4. DAS 2020 Keynote Speech | Adobe 文档分析技术介绍
  5. 数据部门如何All In AI
  6. hibernate 映射 数据库number 映射为 double 为空 报错问题
  7. php sql 字段不能为空值,关于php:Sudden SQL问题-一般错误:1364字段没有默认值
  8. 中介者模式(Mediator) 笔记
  9. 算法在岗一年的经验总结
  10. Java编程:栈的应用实例——逆波兰计算器
  11. Alamofire和AFNetworking中https相关知识点
  12. 数学几何定理 与 13个基本不等式
  13. php表格行数怎么设置,表格怎么排版
  14. 我的缅甸往事(二) | 惊魂南塘河
  15. 2019_WSDM_Session-Based Social Recommendation via Dynamic Graph Attention Networks
  16. 麻将算法(二)牌型转换以及接牌
  17. VMware虚拟机不能识别U盘 的解决方法
  18. java中控制反转_Java如何利用IOC控制反转的三种设计模式详解
  19. OpenCV实战之人脸美颜美型(四)——肤色检测
  20. 万字总结,体系化带你全面认识 Kube-Proxy IPVS 模式的工作原理

热门文章

  1. linux下安装mysql5.7.11全纪录_记一次linux下安装mysql5.7
  2. 面试记录-KPMG(毕马威)
  3. 【ORBSLAM2点线融合】空间直线参数化
  4. 电梯实时智能监测与诊断:应用人工智能的案例研究和解决方案
  5. 现场调试——win7 X64安装VS2017闪退之kb4474419 终极办法
  6. nginx配置实现代理多个内网地址
  7. sql语句实现动态添加查询条件
  8. 原神手游显示无法连接服务器,原神手游进不去怎么办 游戏无法登录解决方法...
  9. CrystalDiskMark简介
  10. 三目表达式 ---if--else的简写