[BZOJ4503]两个串(快速傅立叶变换FFT)
来源:互联网 发布:反美颜软件有可能 编辑:程序博客网 时间:2024/06/01 07:49
Description
兔子们在玩两个串的游戏。给定两个字符串S和T,兔子们想知道T在S中出现了几次,
分别在哪些位置出现。注意T中可能有“?”字符,这个字符可以匹配任何字符。
Input
两行两个字符串,分别代表S和T
Output
第一行一个正整数k,表示T在S中出现了几次
接下来k行正整数,分别代表T每次在S中出现的开始位置。按照从小到大的顺序输出,S下标从0开始。
Sample Input
bbabaababaaaaabaaaaaaaabaaabbbabaaabbabaabbbbabbbbbbabbaabbbababababbbbbbaaabaaabbbbbaabbbaabbbbabab
a?aba?abba
Sample Output
0
HINT
S 长度不超过 10^5, T 长度不会超过 S。 S 中只包含小写字母, T中只包含小写字母和“?”
这题酷似kmp,但是由于有通配符”?”的存在,所以并不能用。
那么可以把“匹配”这个概念转化为
因为有通配符的存在
那么子串匹配也就是求
∑lenT−1j=0Tj(Si−Tj)2=0
把这个式子展开来
∑lenT−1j=0Tj(S2i−2SiTj+T2j)=0
∑lenT−1j=0TjS2i−2SiT2j+T3j=0
其实
∑lenT−1j=0TjS2j+x−2Sj+xT2j+T3j=0
进而
∑lenT−1j=0TjS2j+x−∑lenT−1j=02Sj+xT2j+∑lenT−1j=0T3j=0
最后一个我们暂时不用去管,先看前面两个。
因为卷积满足函数的下标和不变,但是这两个是差不变,那么我们考虑把其中一个函数反转,使其满足卷积下标和不变的性质。
令
∑lenT−1j=0TlenT−j−1S2j+x−∑lenT−1j=02Sj+xT2lenT−j−1+∑lenT−1j=0T3lenT−j−1=0
然后我们再发现
但事实上,这是等效的,因为
那么三次fft求解即可
code:
#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<iostream>using namespace std;typedef long long LL;const int maxn=110000;const double pi=acos(-1.0);struct complex{ double r,i; complex() {} complex(double _r,double _i) {r=_r,i=_i;} friend complex operator + (const complex &x,const complex &y) {return complex(x.r+y.r,x.i+y.i);} friend complex operator - (const complex &x,const complex &y) {return complex(x.r-y.r,x.i-y.i); } friend complex operator * (const complex &x,const complex &y) {return complex(x.r*y.r-x.i*y.i,x.r*y.i+x.i*y.r);}} a[maxn*4],b[maxn*4],c[maxn*4];int R[maxn*4];void fft(complex *y,int len,int on){ for(int i=0; i<len; i++)if(i<R[i])swap(y[i],y[R[i]]); for(int i=1; i<len; i<<=1) { complex wn(cos(pi/i),sin(on*pi/i)); for(int j=0; j<len; j+=(i<<1)) { complex w(1,0); for(int k=0; k<i; k++,w=w*wn) { complex u=y[j+k]; complex v=w*y[j+k+i]; y[j+k]=u+v; y[j+k+i]=u-v; } } } if(on==-1)for(int i=0; i<len; i++)y[i].r/=len;}inline int get(char c){ if(c>='a' && c<='z') return c-'a'+1; else return 0;}char s1[maxn*4],s2[maxn*4];int S[maxn*4],T[maxn*4];int main(){ int lenS,lenT; scanf("%s",s1); lenS=strlen(s1); for(int i=0; i<lenS; i++) S[i]=get(s1[i]); scanf("%s",s2); lenT=strlen(s2); for(int i=0; i<lenT; i++) T[i]=get(s2[lenT-i-1]); int m=lenS+lenT,n,L=0; for(n=1; n<=m; n*=2) L++; for(int i=0; i<n; i++) R[i]=(R[i>>1]>>1)|(i&1)<<(L-1); for(int i=0; i<n; i++) a[i]=complex(S[i]*S[i],0); for(int i=0; i<n; i++) b[i]=complex(T[i],0); fft(a,n,1); fft(b,n,1); for(int i=0; i<n; i++) c[i]=c[i]+a[i]*b[i]; for(int i=0; i<n; i++) a[i]=complex(1,0); for(int i=0; i<n; i++) b[i]=complex(T[i]*T[i]*T[i],0); fft(a,n,1); fft(b,n,1); for(int i=0; i<n; i++) c[i]=c[i]+a[i]*b[i]; for(int i=0; i<n; i++) a[i]=complex(S[i]*2,0); for(int i=0; i<n; i++) b[i]=complex(T[i]*T[i],0); fft(a,n,1); fft(b,n,1); for(int i=0; i<n; i++) c[i]=c[i]-a[i]*b[i]; fft(c,n,-1); int ans=0; for(int i=0; i<lenS-lenT+1; i++) if(c[i+lenT-1].r<0.5) ans++; printf("%d\n",ans); for(int i=0; i<lenS-lenT+1; i++) if(c[i+lenT-1].r<0.5) printf("%d\n",i); return 0;}
- [BZOJ4503]两个串(快速傅立叶变换FFT)
- bzoj4503两个串 快速傅里叶变换(FFT)
- [BZOJ4503]两个串(FFT)
- Bzoj4503 两个串 FFT
- 快速傅立叶变换(FFT)
- 快速傅立叶变换(FFT)
- 【FFT-快速傅立叶变换】
- 快速傅立叶变换FFT
- Bzoj4503:两个串:FFT,构造
- 快速傅立叶变换算法 FFT
- 快速傅立叶变换(FFT)的C++实现
- 快速傅立叶变换(FFT)的C#代码
- 快速傅立叶变换(FFT)C语言函数
- [UOJ34]多项式乘法(快速傅立叶变换FFT)
- [codevs3123]大整数乘法(快速傅立叶变换FFT)
- 第一次邂逅快速傅立叶变换(FFT)
- FFT快速傅立叶变换的工作原理
- 第一次邂逅快速傅立叶变换(FFT)
- Xlistview
- sql常用语句
- Character.UnicodeBlock中cjk的说明
- Scrapyd 使用
- 深入理解 Java 垃圾回收机制
- [BZOJ4503]两个串(快速傅立叶变换FFT)
- Python SMTP服务发送邮件
- Webpack3的使用(五)
- mysql数据库授权操作
- 篇外篇【今天参加了一个区块链项目的私募,说说内心的感觉】
- bing搜索
- 简单了解阿里云批量计算(上篇)
- 2017-12-19作业 if和switch的使用
- jQuery.ajax() 函数详解,很全很好