Bzoj4259 残缺的字符串
2017-03-06 18:31
127 查看
Submit: 387 Solved: 93
Description
很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n。可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺。 你想对这两个串重新进行匹配,其中A为模板串,那么现在问题来了,请回答,对于B的每一个位置i,从这个位置开始连续m个字符形成的子串是否可能与A串完全匹配?
Input
第一行包含两个正整数m,n(1<=m<=n<=300000),分别表示A串和B串的长度。 第二行为一个长度为m的字符串A。 第三行为一个长度为n的字符串B。 两个串均仅由小写字母和*号组成,其中*号表示相应位置已经残缺。
Output
第一行包含一个整数k,表示B串中可以完全匹配A串的位置个数。 若k>0,则第二行输出k个正整数,从小到大依次输出每个可以匹配的开头位置(下标从1开始)。
Sample Input
3 7a*b
aebr*ob
Sample Output
21 5
HINT
Source
数学问题 FFT 字符串 脑洞题
题解看这里→ http://www.cnblogs.com/SilverNebula/p/6511330.html
这道题只不过给两个串都加了通配符而已。只要在之前那道题的式子上再乘一个a[i]就可以了。
跑得巨慢,尝试优化各种地方,在submission status上留下了一串红。
最后发现我的FFT板子之前是用来处理等长卷积的,所以长度直接设成len*2,实际上只用len(a)+len(b)就可以了(第43行)
速度快了一倍,4768ms成功rank7
↑在此之前手写复数类从1w+优化9000ms
/*by SilverN*/ #include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<vector> using namespace std; const double pi=acos(-1.0); const int mxn=1150011; struct com{ double a,b; com operator + (const com y){return (com){a+y.a,b+y.b};} com operator - (const com y){return (com){a-y.a,b-y.b};} com operator * (const com y){return (com){a*y.a-b*y.b,a*y.b+b*y.a};} }c[mxn],d[mxn],e[mxn]; double a[mxn],b[mxn]; int n,l; int rev[mxn]; void FFT(com *a,int flag){ int i,j,k; for(i=0;i<n;i++){if(rev[i]>i)swap(a[rev[i]],a[i]);} for(i=1;i<n;i<<=1){ com wn=(com){cos(pi/i),flag*sin(pi/i)}; for(j=0;j<n;j+=(i<<1)){ com w=(com){1,0}; for(k=0;k<i;k++,w=w*wn){ com x=a[j+k],y=w*a[i+j+k]; a[j+k]=x+y; a[i+j+k]=x-y; } } } if(flag==-1)for(i=0;i<n;i++)a[i].a/=n; } char s1[300021],s2[300021]; int ans[mxn],cnt=0; int main(){ int l1,l2; scanf("%d%d",&l2,&l1); int i,j; scanf("%s",s2);scanf("%s",s1); int m=l1+l2; for(n=1;n<m;n<<=1)l++; for(i=0;i<n;i++){rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));} for(i=0;i<l1;i++){ if(s1[i]!='*')a[i]=s1[i]-'a'+1; else a[i]=0; } for(i=0;i<l2;i++){ if(s2[i]!='*')b[l2-i-1]=s2[i]-'a'+1; else b[l2-i-1]=0; } for(i=0;i<l1;i++){ c[i].a=a[i]*a[i]*a[i]; } for(i=0;i<l2;i++){ d[i].a=b[i]; } FFT(c,1);FFT(d,1); for(i=0;i<n;i++){e[i]=c[i]*d[i];}//a^3*b // // memset(c,0,sizeof c); // memset(d,0,sizeof d); for(i=0;i<n;i++){c[i].a=a[i]*a[i];c[i].b=0;} for(i=0;i<n;i++){d[i].a=b[i]*b[i];d[i].b=0;} FFT(c,1);FFT(d,1); com tmp=(com){2,0}; for(i=0;i<n;i++){e[i]=e[i]-c[i]*d[i]*tmp;}//2ab*a*b // // memset(c,0,sizeof c); // memset(d,0,sizeof d); for(i=0;i<n;i++){c[i].a=a[i];c[i].b=0;} for(i=0;i<n;i++){d[i].a=b[i]*b[i]*b[i];d[i].b=0;} FFT(c,1);FFT(d,1); for(i=0;i<n;i++){e[i]=e[i]+c[i]*d[i];}//b^3*a // FFT(e,-1); for(i=l2-1;i<l1;i++) if(abs(e[i].a)<=0.5){ ans[++cnt]=i-l2+2; } printf("%d\n",cnt); for(i=1;i<=cnt;i++){ printf("%d ",ans[i]); } return 0; }
相关文章推荐
- BZOJ4259 - 残缺的字符串
- BZOJ4259: 残缺的字符串
- BZOJ4259:残缺的字符串(FFT与字符串匹配)
- 【BZOJ4259】残缺的字符串-FFT
- BZOJ4259 : 残缺的字符串
- bzoj 4259: 残缺的字符串
- [BZOJ4259] 残缺的字符串 FFT
- bzoj4259 残缺的字符串(字符串+fft)
- ●Codevs 4158 残缺的字符串
- BZOJ 4259 残缺的字符串
- [bzoj4259][bzoj4503] 残缺的字符串 [FFT]
- 【BZOJ4259】残缺的字符串 FFT
- 【bzoj4259/bzoj4503】残缺的字符串/两个串 FFT
- BZOJ 4259 残缺的字符串(FFT)
- bzoj 4259 残缺的字符串
- UTF-8编码)将字符串写入文件,当字符串中包含中文时,出现写入文件的数据残缺,而当不包含中文时,写入文件的数据正常
- bzoj4259: 残缺的字符串
- BZOJ 4259: 残缺的字符串(构造+FFT)
- BZOJ4259 残缺的字符串 【fft】
- 带中文的字符串数据写入文件出现数据残缺