正题

题目链接:https://www.luogu.com.cn/problem/P4173


题目大意

给出两个字符串\(S,T\),其中包含小写字母和一些\(?\),\(?\)可以匹配任何字符。

求有多少个\(p\)使得\(T_{0\sim |t|-1}=S_{p\sim p+|t|-1}\)


解题思路

如果不考虑\(?\),我们可以用做差法来匹配两个字符,构造匹配函数

\[f(x)=\sum_{i=0}^{m}(T_i-S_{x+i})^2
\]

这样若\(f(x)=0\)证明它们在位置\(x\)处匹配。

但是现在有\(?\),也就是要跳过有\(?\)的位置,定义\(?\)的值为\(0\),然后改一下匹配函数

\[f(x)=\sum_{i=0}^{m}(T_i-S_{x+i})^2T_iS_{x+i}
\]

展开二次项

\[f(x)=\sum_{i=0}^{m}T_i^3S_{x+i}-2T_{i}^2S_{x+i}^2+T_iS_{x+i}^3
\]

把\(T\)反过来就是\(\sum_{i=0}^{m}T_{m-i-1}^3S_{x+i}-2T_{m-i-1}^2S_{x+i}^2+T_{m-i-1}S_{x+i}^3\)

然后有三个式子卷积之后加起来就好了。

常数极大,开\(\text{-O2}\)才能过。时间复杂度\(O(n\log n)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define int long long
using namespace std;
const int N=1e6+2e5;
const double Pi=acos(-1);
struct complex{
double x,y;
complex(double xx=0,double yy=0)
{x=xx;y=yy;return;}
};
complex operator+(complex a,complex b)
{return complex(a.x+b.x,a.y+b.y);}
complex operator-(complex a,complex b)
{return complex(a.x-b.x,a.y-b.y);}
complex operator*(complex a,complex b)
{return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
struct poly{
complex a[N];
}F[3],G[3];
int n,m,r[N],k;
char s[N],t[N];
queue<int> q;
void FFT(complex *f,int op,int n){
for(int i=0;i<n;i++)
if(i<r[i])swap(f[i],f[r[i]]);
for(int p=2;p<=n;p<<=1){
int len=p>>1;
complex tmp(cos(Pi/len),sin(Pi/len)*op);
for(int k=0;k<n;k+=p){
complex buf(1,0);
for(int i=k;i<k+len;i++){
complex tt=buf*f[i+len];
f[i+len]=f[i]-tt;
f[i]=f[i]+tt;
buf=buf*tmp;
}
}
}
if(op==-1)
for(int i=0;i<n;i++)
f[i].x/=(double)n;
return;
}
void mul(poly &a,poly &b){
FFT(a.a,1,k);FFT(b.a,1,k);
for(int i=0;i<k;i++)
a.a[i]=a.a[i]*b.a[i];
FFT(a.a,-1,k);
return;
}
signed main()
{
scanf("%d%d",&m,&n);
scanf("%s",t);scanf("%s",s);
for(int i=0;i<n;i++){
char c=s[i];int z=s[i]-'a'+1;
if(c=='*')z=0;
F[0].a[i]=complex(z*z*z,0);
F[1].a[i]=complex(z*z,0);
F[2].a[i]=complex(z,0);
}
for(int i=0;i<m;i++){
char c=t[m-i-1];int z=c-'a'+1;
if(c=='*')z=0;
G[0].a[i]=complex(z,0);
G[1].a[i]=complex(z*z,0);
G[2].a[i]=complex(z*z*z,0);
}
k=1;for(k=1;k<=2*n;)k<<=1;
for(int i=0;i<k;i++)
r[i]=(r[i>>1]>>1)|((i&1)?(k>>1):0);
mul(F[0],G[0]);mul(F[1],G[1]);mul(F[2],G[2]);
for(int i=0;i<k;i++)
F[0].a[i].x=F[0].a[i].x-2.0*F[1].a[i].x+F[2].a[i].x;
k=0;
for(int i=0;i<=n-m;i++)
if(fabs(F[0].a[i+m-1].x)<0.5)
k++,q.push(i);
printf("%d\n",k);
while(!q.empty())
printf("%d ",q.front()+1),q.pop();
return 0;
}

P4173-残缺的字符串【FFT】的更多相关文章

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

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

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

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

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

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

  4. P4173 残缺的字符串 fft

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

  5. luoguP4173 残缺的字符串 FFT

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

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

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

  7. 【BZOJ4259】残缺的字符串 FFT

    [BZOJ4259]残缺的字符串 Description 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时, ...

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

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

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

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

  10. P4173 残缺的字符串(FFT)

    [Luogu4173] 题解 \(1.\)定义匹配函数 \(2.\)定义完全匹配函数 \(3.\)快速计算每一位的完全匹配函数值 #include<cstdio> #include< ...

随机推荐

  1. 《深入浅出vue.js》阅读笔记之(object)变化侦测

    1.什么是变化侦测? 通常,在运行时应用内部的状态会不断发生变化,此时需要不停地重新渲染页面,这时如何确定状态中发生了什么变化? 变化侦测就是用来解决这个问题的,它分为两种类型,一种是"推& ...

  2. linux 端口80占用问题

    主要是搭建一次ghost博客网站改成80端口无法启动提示被占用. 提示:80端口被占用,启动失败. netstat -ano 或者 netstat -apn | grep 80 没有发现占用80端口的 ...

  3. 刷题-力扣-剑指 Offer II 055. 二叉搜索树迭代器

    剑指 Offer II 055. 二叉搜索树迭代器 题目链接 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/kTOapQ 著作权归领扣网络所有 ...

  4. spring-data-redis 连接泄漏,我 TM 人傻了

    本系列是 我TM人傻了 系列第四期[捂脸],往期精彩回顾: 升级到Spring 5.3.x之后,GC次数急剧增加,我TM人傻了 这个大表走索引字段查询的 SQL 怎么就成全扫描了,我TM人傻了 获取异 ...

  5. 手动设置IDEA失效的配置文件

  6. 硬核! Github上 ,star超高的Java 开源项目分享给你!

    Awsome JavaGreat Java project on Github(Github 上非常棒的 Java 开源项目). English Version 大家都知道 Github 是一个程序员 ...

  7. MySQL-Cluster 初识

          最近,对mysql-cluster进行初步了解,发现和oracle提供的RAC有一定的相似之处,但区别又很大,下面主要是mysql-cluster的搭建,至于对其的深入了解,留着以后工作需 ...

  8. Redis中关于key的操作指令

    1.keys: 例如: 2.exists 3.move 将指定的数据移动到指定的库 4.expire 5.tt1 6.type 7.rename 8.del

  9. Activiti 学习(一)—— Activiti 基础

    工作流概述 在一个公司中,每一项业务的开始和结束,都可以理解为一个工作流,例如,公司的费用报销的基本流程如下: 如图所示的工作流:员工先提出费用报销申请,提交该申请给部门领导,部门领导审批后,再提交给 ...

  10. Element UI:级联选择器Cascader_动态加载_多级请求不同接口(已知第一级调取第二级)

    ELEMENT UI_CASCADER 使用过饿了么级联动态加载的小伙伴应该都知道,lazyLoad本身是一个无差别返回渲染结点的函数. 当我们存在一个需求:已知级联选择器的第一级结点,现在需要通过第 ...