COGS2216 你猜是不是KMP
第一道自己写的FFT......
不知为啥这题在网上找不到题解......真是麻烦,害得我推了半天......
还是写个简要题解吧......
首先把S和T拆成序列,a~z分别对应成1~26,?是0,设拆成的两个序列分别为A和B。
如果从i开始可以S匹配上T,那么就有
\begin{align}\sum_{j=0}^{m-1}[|A_{i+j}-B_j|=0 \space or \space B_j=0]=m\end{align}
换一个等价写法:
\begin{align}\sum_{j=0}^{m-1}(A_{i+j}-B_j)^2 B_j=0\end{align}
求出所有i对应的值就可以得知每一位是否匹配了。
展开之后发现并没有什么用,这个式子只能$O(n^2)$计算,还不如朴素匹配呢,这玩意儿有个卵用啊(╯‵□′)╯︵┻━┻
尝试把T反转,原式变为
\begin{align}\sum_{j=0}^{m-1}(A_i-B_{m-j-1})^2 B_{m-j-1}\end{align}
展开得
\begin{align}\sum_{j=0}^{m-1}A_{i+j}^2 B_{m-j-1}-2A_{i+j}B_{m-j-1}^2+B_{m-j-1}^3\end{align}
有没有发现这个式子看着有点眼熟......
前两项下标之和都是i+m-1,因此可以看成一个卷积形式,而令最后一项再卷上一个各项全为1的序列(显然不影响结果是吧......),也是卷积,而下标之和是i+m-1,因此定义我们得到的结果为
\begin{align}C_{i+m-1}=\sum_{j=0}^{m-1}A_{i+j}^2 B_{m-j-1}-2A_{i+j}B_{m-j-1}^2+1B_{m-j-1}^3\end{align}
令$D_i=A_i^2,E_i=B_i^2,F_i=B_i^3,I_i=1$,再写成卷积形式就是
\begin{align}C=D*B-2A*E+F*I\end{align}
分别求出三个卷积之后加一下就行了,FFT加速卷积即可,复杂度$O(nlogn)$。
然而常数大如狗,跑的比bitset慢到不知哪儿去了
求出三个卷积的和之后扫一遍判断哪些i对应的$C_{i+m-1}$是0,是的话说明两串在i位置匹配,否则不匹配。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=;
const double pi=acos(-1.0),eps=1e-;
struct Complex{
double a,b;
Complex(double a=0.0,double b=0.0):a(a),b(b){}
Complex operator+(const Complex &x)const{return Complex(a+x.a,b+x.b);}
Complex operator-(const Complex &x)const{return Complex(a-x.a,b-x.b);}
Complex operator*(const Complex &x)const{return Complex(a*x.a-b*x.b,a*x.b+b*x.a);}
Complex &operator*=(const Complex &x){return *this=*this*x;}
}A[maxn],B[maxn],C[maxn],D[maxn],E[maxn],F[maxn],I[maxn];//D是A每项取平方,E是b每项取平方,F是b每项取立方,I是伪单位元
void FFT(Complex*,int,int);
char S[maxn],T[maxn];
int n,m,N=,ans=;
int main(){
freopen("guess.in","r",stdin);
freopen("guess.out","w",stdout);
scanf("%s%s",S,T);
n=strlen(S);
m=strlen(T);
while(N<n+m)N<<=;
for(int i=;i<N;i++)I[i].a=1.0;
for(int i=;i<n;i++){
A[i].a=S[i]-'a'+;
D[i].a=A[i].a*A[i].a;
}
reverse(T,T+m);
for(int i=;i<m;i++){
B[i].a=(T[i]=='?')?:T[i]-'a'+;
E[i].a=B[i].a*B[i].a;
F[i].a=B[i].a*E[i].a;
}
FFT(A,N,);
FFT(B,N,);
FFT(D,N,);
FFT(E,N,);
FFT(F,N,);
FFT(I,N,);//woc,这么多FFT慢不慢啊
for(int i=;i<N;i++){
D[i]*=B[i];
A[i]*=E[i];
F[i]*=I[i];//printf("I[%d]=(%lf,%lf)\n",i,I[i].a,I[i].b);
}
FFT(A,N,-);
FFT(D,N,-);
FFT(F,N,-);
for(int i=;i<n;i++){
//printf("i=%d i+m-1=%d A[i+m-1]=(%lf,%lf) D[i+m-1]=(%lf,%lf) F[i+m-1]=(%lf,%lf)\n",i,i+m-1,A[i+m-1].a,A[i+m-1].b,D[i+m-1].a,D[i+m-1].b,F[i+m-1].a,F[i+m-1].b);
C[i].a=D[i].a-A[i].a*+F[i].a;
}
for(int i=;i+m<=n;i++)if(C[i+m-].a<eps)ans++;
printf("%d\n",ans);
for(int i=;i+m<=n;i++)if(C[i+m-].a<eps)printf("%d\n",i);
return ;
}
void FFT(Complex *A,int n,int tp){
for(int i=,j=,k;i<n-;i++){
k=N;
do{
k>>=;
j^=k;
}while(j<k);
if(i<j)swap(A[i],A[j]);
}
for(int k=;k<=n;k<<=){
Complex wn(cos(-tp**pi/k),sin(-tp**pi/k));
for(int i=;i<n;i+=k){
Complex w(1.0,0.0);
for(int j=;j<(k>>);j++,w*=wn){
Complex a=A[i+j],b=w*A[i+j+(k>>)];
A[i+j]=a+b;
A[i+j+(k>>)]=a-b;
}
}
}
if(tp<)for(int i=;i<n;i++)A[i].a/=n;
}
/*
把T反转,把S和T变成多项式a和b,令
c[i+m-1]=sum{(a[i+j]-b[m-j-1])^2*b[m-j-1]}
显然只有c是0的位置两串才会匹配,展开得
c[i+m-1]=sum{a[i+j]^2*b[m-j-1]-2*a[i+j]*b[m-j-1]^2+b[m-j-1]^3}
前两项是卷积形式,第三项乘上一个伪单位元也是卷积形式,FFT加速即可
*/
ps:其实对$I$跑的那个DFT完全没必要,手动逐项赋成1就行了,然后发现$F$卷完了$I$根本没有什么变化,所以直接对$F$做一下DFT再IDFT回去即可,把$I$写进去只是为了理解式子方便......
UPD:脑残了……那个ps是错的,忽视掉吧……
COGS2216 你猜是不是KMP的更多相关文章
- 快速傅里叶变换(FFT):COGS 2216. 你猜是不是KMP
2216. 你猜是不是KMP ★★★☆ 输入文件:guess.in 输出文件:guess.out 简单对比时间限制:1 s 内存限制:256 MB [题目描述] XX在玩两个串的游戏. ...
- FFT板子
woc......FFT这玩意儿真坑...... 一上午除了打了几遍板子什么也没干......真是废了...... 你要加油啊...... #include<cstdio> #includ ...
- OI总结(垃圾排版就忽略了吧)
学OI一年了,到现在联赛所需要的知识已经基本学完了.现在,有必要回过头来,总结总结自己一年来学到的知识以及得到的经验教训. 基础 语言基础 C++的语言基础啥的就略了吧. 算法复杂度分析 O:复杂度的 ...
- KMP算法求解
// KMP.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> using namespac ...
- 简单有效的kmp算法
以前看过kmp算法,当时接触后总感觉好深奥啊,抱着数据结构的数啃了一中午,最终才大致看懂,后来提起kmp也只剩下“奥,它是做模式匹配的”这点干货.最近有空,翻出来算法导论看看,原来就是这么简单(先不说 ...
- KMP算法
KMP算法是字符串模式匹配当中最经典的算法,原来大二学数据结构的有讲,但是当时只是记住了原理,但不知道代码实现,今天终于是完成了KMP的代码实现.原理KMP的原理其实很简单,给定一个字符串和一个模式串 ...
- 萌新笔记——用KMP算法与Trie字典树实现屏蔽敏感词(UTF-8编码)
前几天写好了字典,又刚好重温了KMP算法,恰逢遇到朋友吐槽最近被和谐的词越来越多了,于是突发奇想,想要自己实现一下敏感词屏蔽. 基本敏感词的屏蔽说起来很简单,只要把字符串中的敏感词替换成"* ...
- [KMP]【学习笔记】
Oulipo Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 36916 Accepted: 14904 Descript ...
- KMP算法实现
链接:http://blog.csdn.net/joylnwang/article/details/6778316 KMP算法是一种很经典的字符串匹配算法,链接中的讲解已经是很明确得了,自己按照其讲解 ...
随机推荐
- flask开发笔记
目录 虚拟环境 Debug模式 配置文件 url传入参数 url反转 重定义向 模板 创建 jinjia2语法 模板继承 flash 加载静态文件 MySQL数据库命令 配置 更新.提交.删除 模型操 ...
- odoo 二次开发的一些原理
一:self是什么 目前新版的Odoo中使用到的self,是对 游标cr.用户ID.模型.上下文.记录集.缓存 的封装. 我们可以通过 self.XX 获取到这些封装的东西,比如:self.cr. ...
- CentOS7 firewalld打开关闭防火墙 开放端口
firewalld的基本使用 启动: systemctl start firewalld 关闭: systemctl stop firewalld 查看状态: systemctl status fir ...
- float 浮动 文档流和文字流区别
关于float属性的脱离文档流的问题 使用float浮动后,元素虽然会脱离文档流,但还处在文本流的位置当中,所以就不会出现重叠的效果吗? 下面我自己试了一下,给两个DIV分别设置了样式,而只给第一个D ...
- List与IList的区别
在我看一个源程序的时候看到这个例子使用了IList<T>返回类型,因为上午刚刚总结过List<T>的详细用法,突然出现了IList<T>,感觉很奇怪,于是上网搜集了 ...
- unity2018的坑点
发布后有的电脑无法运行exe程序(反正我的电脑不行) 删除发布出来的一个叫UnityCrashHandler64.exe即可运行
- 【LESS系列】简介和使用
LESS —— 一个CSS预编译框架,它在CSS的语法基础之上,引入了变量.Mixin(混入).运算以及函数等功能,大大简化了CSS的编写,并且降低了CSS的维护成本,就像它的名称所说的那样,LESS ...
- 1.5 js基础
1.变量.参数.return可以装任何东西. 2.什么时候使用window.onload? 当操作元素时 3.日期对象:在创建日期对象的时候它的日期是不会改变的. ...
- 《c++primer》疑惑记录
第4章 96页,数组维数为变量 第8章 246. IO对象不可复制.赋值原因是类设计时复制构造函数.赋值函数是私有的,为什么这么设计呢? 251. tie举例 第15章 484 派生类可以恢复,但不可 ...
- 错误:严重: Servlet.service() for servlet [appServlet] in context with path [] threw exception [Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is
严重: Servlet.service() for servlet [appServlet] in context with path [] threw exception [Request proc ...