[bzoj4503]&[caioj1455][FFT]串
来源:互联网 发布:金太阳手机炒股软件 编辑:程序博客网 时间:2024/05/29 02:44
【题意】
给定两个字符串a(长度<=10^5)和b(长度<=a),求b在a中出现了几次以及分别在哪些位置出现。
b中会存在“?”字符,这个字符可以匹配所有字母
【输入】
两行两个字符串,分别代表a和b
【输出】
第一行一个正整数m,表示b在a中出现了几次
接下来m行正整数,分别代表b每次在a中出现的开始位置。按照从小到大的顺序输出,a下标从0开始。
【样例输入】
abc
a
【样例输出】
1
0
【题解】
从未想到这么像kmp的题可以用FFT做。。再一次orz了。。
被各路神犇的blogD飞啊。。
题里面最重要的一个东西就是那个?字符
可以匹配任何字符,也就是这个玩意,D掉了kmp。。
我们可以构造出一个卷积,对于两个串,每个串构造这样的卷积
首先反转b数组(FFT做这种题常规做法)
对于a和b,我们构造出卷积的s和t数组
s[i]=a[i]
t[i]=b[i](b[i]≠?)
t[i]=0(b[i]=?)
前提一点,b数组已经反转过来了
那么
只要 (si−tj)^2*tj=0,我们就可以确定,这里开始,a串与b串一定匹配!
1:si=tj即两个字符相等的情况2:si≠tj但是tj=?的情况,我们后面乘的tj可以保证原式答案一定为0
所以如此操作即可
#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<cmath>using namespace std;const double PI=acos(-1.0);const int MAXN=410000;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);}};int R[MAXN];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++) { Complex u=y[k+j]; Complex v=y[k+j+i]*w; y[k+j]=u+v; y[k+j+i]=u-v; w=w*wn; } } } if(on==-1)for(int i=0;i<len;i++)y[i].r/=len;}int s1[MAXN],s2[MAXN];char stx[MAXN],sty[MAXN];int change(char c){ if(c>='a' && c<='z')return c-'a'+1; else return 0;}int n,m,L;Complex a[MAXN],b[MAXN],c[MAXN];int main(){ scanf("%s",stx); scanf("%s",sty); int lenx=strlen(stx),leny=strlen(sty); for(int i=0;i<lenx;i++)s1[i]=stx[i]-'a'+1; for(int i=0;i<leny;i++)s2[i]=change(sty[leny-i-1]); m=lenx+leny;L=0; for(n=1;n<=m;n<<=1)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(s1[i]*s1[i],0); for(int i=0;i<n;i++)b[i]=Complex(s2[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(s1[i]*2,0); for(int i=0;i<n;i++)b[i]=Complex(s2[i]*s2[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(s2[i]*s2[i]*s2[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 cnt=0; for(int i=0;i<lenx-leny+1;i++)if(c[i+leny-1].r<0.5)cnt++; printf("%d\n",cnt); for(int i=0;i<lenx-leny+1;i++)if(c[i+leny-1].r<0.5)printf("%d\n",i); return 0;}
阅读全文
0 0
- [bzoj4503]&[caioj1455][FFT]串
- Bzoj4503 两个串 FFT
- Bzoj4503:两个串:FFT,构造
- [BZOJ4503]两个串(FFT)
- bzoj4503两个串 快速傅里叶变换(FFT)
- [BZOJ4503]两个串(快速傅立叶变换FFT)
- BZOJ4503 两个串
- [bzoj4503]两个串
- bzoj4503 两个串
- [bzoj4503]两个串
- bzoj4503 两个串
- bzoj4503
- 两个串-----FFT妙用!
- 4503: 两个串 FFT
- FFT
- "fft"
- FFT
- fft
- 学会思考,而不只是编程
- Lintcode 二叉树的锯齿形层次遍历
- 寻找旋转排序数组中的最小值
- 使用mysqlreplicate命令快速搭建 Mysql 主从复制
- MySQL5.6X 主从配置
- [bzoj4503]&[caioj1455][FFT]串
- Codeforces Round #428 (Div. 2) E
- iOS之《Effective Objective-C 2.0》读书笔记(8)
- Django+Karlooper+ios重构学校的学生成绩管理系统(二)学生信息管理系统
- 树莓派如何挂载硬盘/U盘
- 'module' object has no attribute 'OP_NO_TLSv1_1'问题解决
- 总结unicode和utf-8的区别
- Android SurfaceView 播放视频
- Mybatis之分页插件——PageHelper