题目大意:

给定两个\((length \leq 10^5)\)的字符串,问第二个串在第一个串中出现了多少次。并且第二个串中含有单字符通配符.

题解:

首先我们从kmp的角度去考虑

这道题从字符串数据结构的方面去考虑你就错了

因为这是我在刷FFT时遇到的题嘛,,直接就去想FFT的做法

我们知道,两个字符串相等当且仅当

\[(\sum_{i=1}^n(s1[i] - s2[i])^2*[s2[i] \neq ?]) = 0
\]

注:可以将s1理解为从第一个串中取出的一个后缀

那么我们对每个s1中的下标就套用公式计算一下即可

我们肯定不能直接计算...

设\(f(x) = \sum_{i=1}^n(s1[o] - s2[i])^2*[s2[i] \neq ?])\)

我们有

\[f(x) = \sum_{i=1}^n(s1[i] - s2[i])^2*[s2[i] \neq ?])
\]

\[f(x) = \sum_{i=1}^ns1[i]^2*s2[i] - \sum{i=1}^n2*s1[i]*s2[i]^2+\sum_{i=1}^ns2[i]^3
\]

针对最后一项求和我们直接预处理即可

有些麻烦的就是前面的两项

但是我们有FFT啊,FFT的作用是计算卷积,可是这明明不是卷积啊?

转化成卷积不就行了。。

我们反转s2这个字符串

然后我们发现,此时有

\[f(x) = \sum_{i=1}^ns1[i]^2*s2[n-i+1] - \sum{i=1}^n2*s1[j]*s2[n-1+1]^2+\sum_{i=1}^ns2[i]^3
\]

前两项变成了标准的卷积形式,所以我们用FFT加速可以在\(nlogn\)内计算

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

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
inline int cat_max(const int &a,const int &b){return a>b ? a:b;}
inline int cat_min(const int &a,const int &b){return a<b ? a:b;}
const int maxn = 210010;
const double pi = acos(-1);
const double eps = 1e-8;
struct complex{
double x,y;
complex(){}
complex(double a,double b){x=a;y=b;}
complex operator + (complex rhs){return complex(x+rhs.x,y+rhs.y);}
complex operator - (complex rhs){return complex(x-rhs.x,y-rhs.y);}
complex operator * (complex rhs){return complex(x*rhs.x-y*rhs.y,x*rhs.y+y*rhs.x);}
complex operator / (double rhs){return complex(x/rhs,y/rhs);}
};
complex a[maxn<<1],b[maxn<<1],c[maxn<<1];
void FFT(complex *x,int n,int p){
for(int i=0,t=0;i<n;++i){
if(i > t) swap(x[i],x[t]);
for(int j = n>>1;(t^=j) < j;j >>= 1);
}
for(int m=2;m<=n;m<<=1){
complex wn(cos(p*2*pi/m),sin(p*2*pi/m));
for(int i=0;i<n;i+=m){
complex w(1,0),u;
int k = m>>1;
for(int j=0;j<k;++j,w=w*wn){
u = x[i+j+k]*w;
x[i+j+k] = x[i+j] - u;
x[i+j] = x[i+j] + u;
}
}
}
if(p == -1) for(int i=0;i<n;++i) x[i] = x[i]/n;
}
char tmp[maxn];
int s1[maxn],s2[maxn];
int main(){
scanf("%s",tmp);int n = strlen(tmp);
for(int i=0;i<n;++i) s1[i] = tmp[i] - 'a' + 1;
scanf("%s",tmp);int m = strlen(tmp);
double sum = 0.0;
for(int i=0;i<m;++i){
s2[m-i-1] = tmp[i] == '?' ? 0 : tmp[i] - 'a' + 1;
sum += s2[m-i-1]*s2[m-i-1]*s2[m-i-1];
} int len = 0;
for(int i=1;(i>>2)<n;i<<=1) len = i;
for(int i=0;i<n;++i) a[i] = complex(s1[i]*s1[i],0);
for(int i=0;i<m;++i) b[i] = complex(s2[i],0);
FFT(a,len,1);FFT(b,len,1);
for(int i=0;i<len;++i) c[i] = a[i]*b[i];
memset(a,0,sizeof a);memset(b,0,sizeof b);
for(int i=0;i<n;++i) a[i] = complex(s1[i],0);
for(int i=0;i<m;++i) b[i] = complex(s2[i]*s2[i],0);
FFT(a,len,1);FFT(b,len,1);
for(int i=0;i<len;++i) c[i] = c[i] - (a[i]*b[i]) - (a[i]*b[i]);
FFT(c,len,-1);
int ans = 0;
for(int i=m-1;i<n;++i)
if( (int)(c[i].x + sum + 0.5) == 0 ) ++ans;
printf("%d\n",ans);
for(int i=m-1;i<n;++i)
if( (int)(c[i].x + sum + 0.5) == 0 ) printf("%d\n",i-m+1);
getchar();getchar();
return 0;
}

bzoj 4503 两个串 快速傅里叶变换FFT的更多相关文章

  1. bzoj 4503: 两个串【脑洞+FFT】

    真实脑洞题 因为通配符所以导致t串实际有指数级别个,任何字符串相关算法都没有用 考虑一个新的匹配方法:设a串(模板串)长为n,从m串的i位置开始匹配:\( \sum_{i=0}^{n-1}(a[j]- ...

  2. BZOJ 4503: 两个串 [FFT]

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

  3. bzoj 4503 两个串

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

  4. 【刷题】BZOJ 4503 两个串

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

  5. BZOJ 4503 两个串(FFT)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4503 [题目大意] 给出S串和T串,计算T在S中出现次数,T中有通配符'?'. [题解 ...

  6. BZOJ.4503.两个串(FFT/bitset)

    题目链接 \(Description\) 给定两个字符串S和T,求T在S中出现了几次,以及分别在哪些位置出现.T中可能有'?'字符,这个字符可以匹配任何字符. \(|S|,|T|\leq 10^5\) ...

  7. bzoj 4503 两个串——FFT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4503 翻转T,就变成卷积.要想想怎么判断. 因为卷积是乘积求和,又想到相等的话相减为0,所以 ...

  8. bzoj 4503 两个串 —— FFT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4503 推式子即可: 不知怎的调了那么久,应该是很清晰的. 代码如下: #include< ...

  9. BZOJ 4503 两个串 ——FFT

    [题目分析] 定义两个字符之间的距离为 (ai-bi)^2*ai*bi 如果能够匹配,从i到i+m的位置的和一定为0 但这和暴力没有什么区别. 发现把b字符串反过来就可以卷积用FFT了. 听说KMP+ ...

随机推荐

  1. dede列表页调用文章,其实是所有页面都可以调用,第一次应用sql标签

    {dede:sql sql="SELECT aid,typeid,body,userip FROM `#@__addonarticle` where aid='6' or aid='7' o ...

  2. 循序渐进学Python 1 安装与入门

    1 安装 2 使用 2.1 运行程序 3 艺搜参考 by 2013年10月16日 安装 Windows安装版,源码,帮助文档: 使用 打开开始菜单中的Python GUI启动Python解释器: 启动 ...

  3. VS2017快捷键

    1.回到上一个光标位置/前进到下一个光标位置 (1)回到上一个光标位置:使用组合键“Ctrl + -”; (2)前进到下一个光标位置:“Ctrl + Shift + - ”. 2.复制/剪切/删除整行 ...

  4. c# combobox 绑定枚举方式

    建立一个类 : using System; using System.Collections.Generic; using System.Linq; using System.Text; using ...

  5. Java线程:概念及原理

    线程是执行的程序中的一个线程. Java虚拟机允许应用程序必须同时运行多个执行线程. 每个线程都有一个优先事项.具有更高优先级的线程优先于线程的优先级较低的执行.每个线程可能会或可能不会也被标记为一个 ...

  6. Java 集成域登陆

    参考: 1. JAVA中使用jcifs集成AD域用户认证 2. https://liaosy.iteye.com/blog/1887092 3.其他库 https://github.com/Waffl ...

  7. 高复用率的RTSPClient组件EasyRTSPClient设计流程概述

    EasyRTSPClient 设计过程 概述 EasyRTSPClient 基于live555构建而成. 今天讲讲EasyRTSPClient的设计过程 EasyRTSPClient,主要包括以下部分 ...

  8. 九度OJ 1006:ZOJ问题 (递归)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:18621 解决:3197 题目描述: 对给定的字符串(只包含'z','o','j'三种字符),判断他是否能AC. 是否AC的规则如下: 1. ...

  9. iOS与H5交互及UIWebView缓存

    iOS原生App与H5页面交互笔记 最近在做一个项目用到了原生App与H5交互,之前有做过简单的H5页面直接调用原生方法的例子,就是利用UIWebView中的代理方法 //webview每次加载之前都 ...

  10. wepy 实现 用户名登录与短信验证码登录

    wepy 实现 用户名登录与短信验证码登录