【BZOJ4503】两个串(FFT)

题面

给定串\(S\),以及带通配符的串\(T\),询问\(T\)在\(S\)中出现了几次。并且输出对应的位置。

\(|S|,|T|<=10^5\),字符集大小为\(26\)

题解

先来考虑没有通配符怎么匹配。别跟我说KMP!!

根据前面几个题目的套路,我们可以把每个字符分开来考虑,然后将\(T\)串反转,将有这个字符的位置变成\(1\),然后\(FFT\),就可以知道在这一段里面这个字符匹配上了多少个,然后把每个字符求个和,检查是否恰好匹配了\(|T|\)个。

通配符此时并不需要考虑。

时间复杂度\(O(26nlogn)\)

当然,如果您真的这么写了,那么肯定\(T\)飞了。\(FFT\)自带巨大常数。对于字符集很小的时候上述方法是可行的,字符集很大的时候就不能这么做了。

所以我们考虑如何只做一遍\(FFT\)。(没有通配符的情况下)

每个字符当然不能动了,所以把他们对应成数字。如果匹配上了怎么办?那就是上下两个对应的数字相等,可以考虑作差。但是又发现作差可能会使得几个正数和几个负数相加变成\(0\),所以考虑平方。

所以,我们定义每个位置的函数值\(f(x)=\sum_{i=1}^{|T|}(S[x+i-1]-T[i])^2\)

将\(T\)串反转,平方项拆开之后,就变成了两个卷积+一个常数项的形式,直接\(FFT\)然后求和,检查最后的函数值是否为\(0\)就行了。

现在有了通配符,我们不妨令\(a..z\)对应的数字为\(1..26\)。通配符无论给它一个什么数字,它和上面的字符的差的平方一定不为\(0\)。

所以我们换种方法考虑,把通配符对应的数字设为\(0\),但是这样差的平方不是\(0\),所以我们就在上面那个式子后面乘上一个\(T[i]\)的权值,如果此时是通配符就会乘\(0\),从而也变成了\(0\)。这样一来,原来的式子就变成了\(f(x)=\sum_{i=1}^{|T|}(S[x+i-1]-T[i])^2T[i]\)

拆开后是两个卷积+一个常数项的形式,\(FFT\)即可。

时间复杂度\(O(nlogn)\)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 333333
const double Pi=acos(-1);
struct Complex{double a,b;}A1[MAX],B1[MAX],A2[MAX],B2[MAX],W[MAX],F[MAX];
Complex operator+(Complex a,Complex b){return (Complex){a.a+b.a,a.b+b.b};}
Complex operator-(Complex a,Complex b){return (Complex){a.a-b.a,a.b-b.b};}
Complex operator*(Complex a,Complex b){return (Complex){a.a*b.a-a.b*b.b,a.a*b.b+a.b*b.a};}
int n,m,r[MAX],N,Z;
int pos[MAX],ans,l;
char S[MAX],T[MAX];
void FFT(Complex *P,int opt)
{
for(int i=1;i<N;++i)if(i<r[i])swap(P[i],P[r[i]]);
for(int i=1;i<N;i<<=1)
for(int p=i<<1,j=0;j<N;j+=p)
for(int k=0;k<i;++k)
{
Complex w=(Complex){W[N/i*k].a,W[N/i*k].b*opt};
Complex X=P[j+k],Y=w*P[j+k+i];
P[j+k]=X+Y;P[i+j+k]=X-Y;
}
if(opt==-1)for(int i=0;i<N;++i)P[i].a/=N;
}
int main()
{
scanf("%s",S);scanf("%s",T);
n=strlen(S);m=strlen(T);
for(N=1;N<=(n+m-2);N<<=1)++l;
for(int i=0;i<N;++i)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
for(int i=1;i<N;i<<=1)
for(int k=0;k<i;++k)W[N/i*k]=(Complex){cos(k*Pi/i),sin(k*Pi/i)};
for(int i=0;i<n;++i)A1[i].a=(S[i]-96)*(S[i]-96),A2[i].a=2*(S[i]-96);
for(int i=0;i<m;++i)
{
int x=((T[m-i-1]=='?')?0:(T[m-i-1]-96));
B1[i].a=x;B2[i].a=x*x;Z+=x*x*x;
}
FFT(A1,1);FFT(B1,1);FFT(A2,1);FFT(B2,1);
for(int i=0;i<N;++i)
F[i]=A1[i]*B1[i]-A2[i]*B2[i];
FFT(F,-1);
for(int i=m-1;i<n;++i)
if((int)(F[i].a+0.5+Z)==0)pos[++ans]=i-m+1;
printf("%d\n",ans);
for(int i=1;i<=ans;++i)printf("%d\n",pos[i]);
return 0;
}

【BZOJ4503】两个串(FFT)的更多相关文章

  1. bzoj4503: 两个串 bitset

    目录 题目链接 题解 代码 题目链接 bzoj4503: 两个串 题解 暴一发bitset f[i][j] 表示 S[1..i] 是否有个后缀能匹配 T[1..j] 那么假设 S[i+1] 能匹配 T ...

  2. 【BZOJ4503】两个串 FFT

    [BZOJ4503]两个串 Description 兔子们在玩两个串的游戏.给定两个字符串S和T,兔子们想知道T在S中出现了几次, 分别在哪些位置出现.注意T中可能有“?”字符,这个字符可以匹配任何字 ...

  3. 【bzoj4259/bzoj4503】残缺的字符串/两个串 FFT

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

  4. BZOJ4259: 残缺的字符串 & BZOJ4503: 两个串

    [传送门:BZOJ4259&BZOJ4503] 简要题意: 给出两个字符串,第一个串长度为m,第二个串长度为n,字符串中如果有*字符,则代表当前位置可以匹配任何字符 求出第一个字符串在第二个字 ...

  5. BZOJ 4503: 两个串 [FFT]

    4503: 两个串 题意:兔子们在玩两个串的游戏.给定两个只含小写字母的字符串S和T,兔子们想知道T在S中出现了几次, 分别在哪些位置出现.注意T中可能有"?"字符,这个字符可以匹 ...

  6. BZOJ4503: 两个串

    Description 兔子们在玩两个串的游戏.给定两个字符串S和T,兔子们想知道T在S中出现了几次, 分别在哪些位置出现.注意T中可能有“?”字符,这个字符可以匹配任何字符. Input 两行两个字 ...

  7. BZOJ4503 两个串 多项式 FFT

    题目传送门 - BZOJ4503 题意概括 给定两个字符串S和T,回答T在S中出现了几次,在哪些位置出现.注意T中可能有?字符,可以匹配任何字符. 题解 首先,假装你已经知道了这是一道$FFT$题. ...

  8. 2019.02.06 bzoj4503: 两个串(fft)

    传送门 题意简述:给两个字符串s,ts,ts,t,ttt中可能有通配符,问ttt在sss出现的次数和所有位置. 思路:一道很熟悉的题,跟bzoj4259bzoj4259bzoj4259差不多的. 然后 ...

  9. 【bzoj4503】 两个串 FFT

    $FFT$套路题(然而我看错题了) 我们考虑化一下式子. 设当前比较的两个部分为$S[i....i+|T|-1]$和$T[0....|T|-1]$. 我们对串$T$中出现问号的位置全部赋值为$0$. ...

  10. BZOJ4503 两个串 【fft】

    题目链接 BZOJ4503 题解 水水题. 和残缺的字符串那题几乎是一样的 同样转化为多项式 同样TLE 同样要手写一下复数才A #include<algorithm> #include& ...

随机推荐

  1. vue2.0中使用pug(jade)

    第一部分:pug(jade)模板引擎 pug,原名jade,是流行的HTML模板引擎,它是HAML在JavaScript上的实现,最大的特色是使用缩进排列替代成对标签. 它简化了HTML的成对标签的写 ...

  2. Luogu P1447 [NOI2010]能量采集

    Preface 最近反演题做多了看什么都想反演.这道题由于数据弱,解法多种多样,这里简单分析一下. 首先转化下题目就是对于一个点\((x,y)\),所消耗的能量就是\(2(\gcd(x,y)-1)+1 ...

  3. OpenGL学习(1)——创建窗口

    这是我的第一篇博客,试着记录学习OpenGL的过程.使用的教程:LearnOpenGL,系统:Deepin 15.9.3,IDE:Qt Creator. 添加头文件 创建窗口用到两个库:GLFW和GL ...

  4. C_数据结构_递归实现累加

    # include <stdio.h> long sum(int n) { //用递归实现: ) ; else ) + n; /* 用for循环实现: long s = 0; int i; ...

  5. taro之React Native 端开发研究

    初步结论:如果想把 React Native 集成到现有的原生项目中,不能使用taro的React Native 端开发功能(目前来说不能实现,以后再观察).   RN开发有2种模式: 1.一是原生A ...

  6. 12.17 Daily Scrum

      Today's Task Tomorrow's Task 丁辛 实现和菜谱相关的餐厅列表. 实现和菜谱相关的餐厅列表.             邓亚梅             美化搜索框UI. 美 ...

  7. BugPhobia终章篇章:学霸在线系统Beta阶段展示

    0x00 :序言 1 universe, 9 planets, 204 countries,809 islands, 7 seas, and i had the privilege to meet y ...

  8. 《Linux内核分析》第八周学习笔记

    <Linux内核分析>第八周学习笔记 进程的切换和系统的一般执行过程 郭垚 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163 ...

  9. Linux内核分析——进程的切换和系统的一般执行过程

    进程的切换和系统的一般执行过程 一.进程切换的关键代码switch_to分析 (一)进程调度与进程调度的时机分析 1.不同类型的进程有不同的调度需求 第一种分类: (1)I/O-bound:频繁进行I ...

  10. 广商博客冲刺第三天new

    第二天沖刺傳送門 第三四天沖刺傳送門 这一天我们主要是弄网页前台设计跟框架设计,这方面主要是由张奇聪负责.我们在amaze ui,smart ui,angularjs+bootstrap中挑选,最终选 ...