快速傅里叶变换(FFT):COGS 2216. 你猜是不是KMP

2216. 你猜是不是KMP

★★★☆   输入文件:guess.in   输出文件:guess.out   简单对比
时间限制:1 s   内存限制:256 MB

【题目描述】

  XX在玩两个串的游戏。首先,他拿出了两个字符串 S 和 T,XX想知道 T在 S 中出现了几次,分别在哪些位置出现。注意 T 中可能有“?”字符,这个字符可以匹配任何字符。

【输入格式】

  两行两个字符串,分别代表 S 和 T

【输出格式】

  第一行一个正整数 k,表示 T 在 S 中出现了几次。

  接下来 k 行正整数,

  分别代表 T 每次在 S 中出现的开始位置。按照从小到大

  的顺序输出,S 下标从 0 开始。

【样例输入】

  ababcadaca

  a?a

【样例输出】

  3

  0

  5

  7

【提示】

  对于 10%的数据, S 和 T 的长度不超过 100

  对于另外 20%的数据,T 中无“?”

  对于 100%的数据,S 长度不超过 10^5,T 长度不会超过 S。S 中只包含小写

  字母,T 中只包含小写字母和“?”

【来源】

  经典题目

  

  这道题咩,是FFT哦,咳咳……

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <cmath>
  5 using namespace std;
  6 const int maxn=400010;
  7 const double PI=acos(-1.0);
  8 char s[maxn],t[maxn];
  9 int a[maxn],b[maxn];
 10 struct complex{
 11     double r,i;
 12     complex(double r_=0.0,double i_=0.0){
 13         r=r_;i=i_;
 14     }
 15     complex operator +(complex a){
 16         return complex(r+a.r,i+a.i);
 17     }
 18     complex operator -(complex a){
 19         return complex(r-a.r,i-a.i);
 20     }
 21     complex operator *(complex a){
 22         return complex(r*a.r-i*a.i,r*a.i+i*a.r);
 23     }
 24 };
 25 complex A[maxn],B[maxn],C[maxn],D[maxn],E[maxn];
 26
 27 void Rader(complex *a,int len){
 28     int k;
 29     for(int i=1,j=len>>1;i<len-1;i++){
 30         if(i<j)swap(a[i],a[j]);
 31         k=len>>1;
 32         while(j>=k){
 33             j-=k;
 34             k>>=1;
 35         }
 36         j+=k;
 37     }
 38 }
 39
 40 void FFT(complex *a,int len,int on){
 41     Rader(a,len);
 42     for(int h=2;h<=len;h<<=1){
 43         complex wn(cos(-on*PI*2.0/h),sin(-on*PI*2.0/h));
 44         for(int j=0;j<len;j+=h){
 45             complex w(1,0);
 46             for(int k=j;k<j+(h>>1);k++){
 47                 complex u=a[k];
 48                 complex v=a[k+(h>>1)]*w;
 49                 a[k]=u+v;
 50                 a[k+(h>>1)]=u-v;
 51                 w=w*wn;
 52             }
 53         }
 54     }
 55     if(on==-1)
 56         for(int i=0;i<len;i++)
 57             a[i].r/=len;
 58 }
 59 int ans[maxn],tot;
 60 int main(){
 61     freopen("guess.in","r",stdin);
 62     freopen("guess.out","w",stdout);
 63     scanf("%s%s",s,t);
 64     int lens=strlen(s);
 65     int lent=strlen(t);
 66     for(int i=0;i<lens;i++)
 67         a[i]=s[i]-‘a‘+1;
 68     for(int i=0;i<lent;i++){
 69         if(t[i]==‘?‘)
 70             b[lent-i-1]=0;
 71         else
 72             b[lent-i-1]=t[i]-‘a‘+1;
 73     }
 74
 75     int len=1;
 76     while(len<=lens+lent)len<<=1;
 77
 78     for(int i=0;i<lens;i++)A[i]=complex(1.0,0);
 79     for(int i=0;i<lent;i++)B[i]=complex(1.0*b[i]*b[i]*b[i],0);
 80     FFT(A,len,1);FFT(B,len,1);
 81     for(int i=0;i<len;i++)C[i]=A[i]*B[i];
 82     FFT(C,len,-1);
 83
 84     memset(A,0,sizeof(A));
 85     memset(B,0,sizeof(B));
 86     for(int i=0;i<lens;i++)A[i]=complex(2.0*a[i],0);
 87     for(int i=0;i<lent;i++)B[i]=complex(1.0*b[i]*b[i],0);
 88     FFT(A,len,1);FFT(B,len,1);
 89     for(int i=0;i<len;i++)D[i]=A[i]*B[i];
 90     FFT(D,len,-1);
 91
 92     memset(A,0,sizeof(A));
 93     memset(B,0,sizeof(B));
 94     for(int i=0;i<lens;i++)A[i]=complex(1.0*a[i]*a[i],0);
 95     for(int i=0;i<lent;i++)B[i]=complex(1.0*b[i],0);
 96     FFT(A,len,1);FFT(B,len,1);
 97     for(int i=0;i<len;i++)E[i]=A[i]*B[i];
 98     FFT(E,len,-1);
 99
100     for(int i=lent-1;i<lens;i++)
101         if(fabs(C[i].r-D[i].r+E[i].r)<1e-5)
102             ans[++tot]=i-lent+1;
103
104     printf("%d\n",tot);
105     for(int i=1;i<=tot;i++)
106         printf("%d\n",ans[i]);
107     return 0;
108 }
时间: 2024-11-08 21:28:21

快速傅里叶变换(FFT):COGS 2216. 你猜是不是KMP的相关文章

[学习笔记] 多项式与快速傅里叶变换(FFT)基础

引入 可能有不少OIer都知道FFT这个神奇的算法, 通过一系列玄学的变化就可以在 $O(nlog(n))$ 的总时间复杂度内计算出两个向量的卷积(或者多项式乘法/高精度乘法), 而代码量却非常小. 博主一年半前曾经因COGS的一道叫做"神秘的常数 $\pi$"的题目而去学习过FFT, 但是基本就是照着板子打打完并不知道自己在写些什么鬼畜的东西OwO 不过...博主这几天突然照着算法导论自己看了一遍发现自己似乎突然意识到了什么OwO然后就打了一道板子题还1A了OwO再加上午考试差点AK

快速傅里叶变换FFT

快速傅里叶变换FFT DFT是信号分析与处理中的一种重要变换.但直接计算DFT的计算量与变换区间长度N的平方成正比,当N较大时,计算量太大,直接用DFT算法进行谱分析和信号的实时处理是不切实际的. 1.直接计算DFT 长度为N的有限长序列x(n)的DFT为: 2.减少运算量的思路和方法 思路:N点DFT的复乘次数等于N2.把N点DFT分解为几个较短的DFT,可使乘法次数大大减少.另外,旋转因子WmN具有周期性和对称性. (考虑x(n)为复数序列的一般情况,对某一个k值,直接按上式计算X(k)值需

浅谈范德蒙德(Vandermonde)方阵的逆矩阵的求法以及快速傅里叶变换(FFT)中IDFT的原理

浅谈范德蒙德(Vandermonde)方阵的逆矩阵与拉格朗日(Lagrange)插值的关系以及快速傅里叶变换(FFT)中IDFT的原理 只要稍微看过一点线性代数的应该都知道范德蒙德行列式. \[V(x_0,x_1,\cdots ,x_{n-1})=\begin{bmatrix} {1}&{1}&{\cdots}&{1}\{x_{0}}&{x_{1}}&{\cdots}&{x_{n-1}}\{x_{0}^2}&{x_{1}^2}&{\cdots

【笔记篇】(理论向)快速傅里叶变换(FFT)学习笔记w

现在真是一碰电脑就很颓废啊... 于是早晨把电脑锁上然后在旁边啃了一节课多的算导, 把FFT的基本原理整明白了.. 但是我并不觉得自己能讲明白... Fast Fourier Transformation, 快速傅里叶变换, 是DFT(Discrete Fourier Transform, 离散傅里叶变换)的快速实现版本. 据说在信号处理领域广泛的应用, 而且在OI中也有广泛的应用(比如SDOI2017 R2至少考了两道), 所以有必要学习一波.. 划重点: 其实学习FFT最好的教材是<算法导论

【转】快速傅里叶变换(FFT)详解

目录 前言 多项式 系数表示法 点值表示法 复数 向量 圆的弧度制 平行四边形定则 复数 运算法则 单位根 单位根的性质 快速傅里叶变换 快速傅里叶逆变换 理论总结 递归实现 迭代实现 本文只讨论FFT在信息学奥赛中的应用 文中内容均为个人理解,如有错误请指出,不胜感激 回到顶部 前言 先解释几个比较容易混淆的缩写吧 DFT:离散傅里叶变换->O(n2)O(n2)计算多项式乘法 FFT:快速傅里叶变换->O(n?log(n)O(n?log?(n)计算多项式乘法 FNTT/NTT:快速傅里叶变换

快速傅里叶变换FFT学习小记

FFT学得还是有点模糊,原理那些基本还是算有所理解了吧,不过自己推这个推不动. 看的资料主要有这两个: http://blog.miskcoo.com/2015/04/polynomial-multiplication-and-fast-fourier-transform https://www.zybuluo.com/397915842/note/37965 这儿简单做做笔记. 多项式点值表示 首先$FFT$用来快速计算两个多项式的乘积. 一个$n$次多项式(最高次为$n$),可以用系数表示法

图像傅里叶变换(快速傅里叶变换FFT)

学习DIP第7天,图像傅里叶变换 习惯性,开篇废话 今天公司的网不知怎么了,死活打不开CSDN,公司有100多架客机,也有极限速度60kb/s的网速,还有3K的工资. 图像FFT 上篇已经介绍了关于2D FFT的相关知识,这篇只介绍在图像中的应用,对于一幅图像,做二维FFT后,即可得到其傅里叶变换,傅里叶变换后是二维复数矩阵,因为二维数组,如果是实数,是可以通过变换到0~255通过灰度图像显示出来,而变换结果是复数,所以我们通过显示其幅度,即复数的模,来显示傅里叶谱(幅度谱),不废话,上图: 原

几种快速傅里叶变换(FFT)的C++实现

DFT的的正变换和反变换分别为(1)和(2)式.假设有N个数据,则计算一个频率点需要N次复数乘法和N-1次复数加法,整个DFT需要N*N次复数乘 法和N(N-1)次复数加法:由于一次的复数乘法需要进行4次的实数乘法和2次的复数加法,一次的复数加法需要两次的实数加法,因此整个DFT需要 4*N*N次的实数乘法和2*N(N-1)+2*N*N≍4*N*N次的复数加法.当N比较大时,所需的计算工作量相当大,例如N=1024时大约需要 400万次乘法运算,对于实时信号处理来说,将对计算设备提出非常苛刻的要

快速傅里叶变换(FFT)模板

//有多少项N取多至少8~10倍 #include <algorithm> #include <cmath> #include <complex> #include <cstdlib> using namespace std; typedef complex<double> cn; const int N=1e7+1; const double Pi=3.1415926535;//Pi通常取10位即可(随意) cn a[N],b[N]; int