YZOJ P3069 字符串匹配
时间限制:4000MS 内存限制:262144KB
难度:\(7.0\)
-
题目描述
给出两个串 \(A\) 和 \(B\),串中仅包含小写字母和字符 *
,其中 *
能匹配任意的小写字母(也可以匹配 *
)。
请你求出如果以 \(A\) 为模板串,那么有哪些 \(i\) 使得 \(B[i,i+\left|A\right|)\) 可以与 \(A\) 匹配?
-
输入格式
第一行 \(A\),第二行 \(B\) 。
-
输出格式
按照从小到大输出所有 \(i\) 。
-
样例输入
1 2 |
a*b aebr*ob |
-
样例输出
1 |
1 5 |
-
数据规模与约定
对于所有数据,\(\left|A\right|, \left|B\right| \leq 500000\) 。
想法完全偏离正解www
设 *
为 \(0\) ,其余字母的值都与 ASCII 相对应。
构造 Hash \(\sum\limits_{i=0}^{n-1}(A_i-B_i)^2A_iB_i\) ,当且仅当它的值为 \(0\) 时 两字符串完全匹配,因为只有每一位都相等时 它的值才可能为 \(0\) 。(为了消去负数的影响所以有一个平方,考虑到 *
所以再乘上其本身。)
所以可以枚举 \(A\) 在 \(B\) 中的末尾位置 \(i\) ,当这个字串匹配时,有 \(\sum\limits_{j=0}^{m-1}(A_j-B_{i-m+1+j})^2A_jB_{i-m+1+j}=0\) 。
若把 \(A\) 串翻转,同时后面补 \(0\) 至与 \(B\) 串等长,就会有 \(\sum\limits_{j=0}^i(A_j-B_{i-j})^2A_jB_{i-j}=0\) 。
展开,有 \(\sum\limits_{j=0}^iA_{j}^3B_{i-j}-2\sum\limits_{j=0}^iA_j^2B_{i-j}^2+\sum\limits_{j=0}^iA_{j}B_{i-j}^3\) 。
跑三次 FFT 即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
#include <cstdio> #include <cstdlib> #include <cstring> #include <climits> #include <cmath> #include <algorithm> #define eps 1e-3 #define _abs(_x) ((_x)<0?-(_x):(_x)) inline void getstr(char s[],int&ls) { ls=0; register char c=0; while(!(c>='a' && c<='z') && c!='*') c=getchar(); while((c>='a' && c<='z') || c=='*') s[++ls]=c,c=getchar(); } double _ta,_tb; struct _cm { // a+bi double a,b; _cm(double na=0,double nb=0){a=na,b=nb;} #define _cm_plus(_x,_a,_b) ((_x).a=(_a).a+(_b).a,(_x).b=(_a).b+(_b).b) #define _cm_minus(_x,_a,_b) ((_x).a=(_a).a-(_b).a,(_x).b=(_a).b-(_b).b) #define _cm_times(_x,_a,_b) (_ta=(_a).a*(_b).a-(_a).b*(_b).b,_tb=(_a).b*(_b).a+(_a).a*(_b).b,(_x).a=_ta,(_x).b=_tb) }a[3][1050505],b[3][1050505]; int flip[1050505]; inline void FFT(register int len,_cm c[],bool inverse=false) { _cm t; for(register int i=0;i<len;i++) if(i<flip[i]) t=c[i],c[i]=c[flip[i]],c[flip[i]]=t; for(register int step=2;step<=len;step<<=1) { _cm wn(std::cos((double)2*M_PI/step), \ std::sin((double)2*M_PI/step)*(inverse?-1:1)); register int hstep=step>>1; static _cm pw[1050505]; pw[0]=(_cm){1,0}; for(register int k=1;k<=hstep;k++) _cm_times(pw[k],pw[k-1],wn); for(register int k=0;k<len;k+=step) for(register int i=k;i<k+hstep;i++) { register int j=i+hstep; _cm_times(t,c[j],pw[i-k]); _cm_minus(c[j],c[i],t); _cm_plus(c[i],c[i],t); } } if(inverse) for(register int i=0;i<len;i++) c[i].a/=len; } char A[505050],B[505050]; int main() { int lA,lB;getstr(A,lA),getstr(B,lB); for(register int i=1;i<lA-i+1;i++) A[i]^=A[lA-i+1]^=A[i]^=A[lA-i+1]; register int len=1,dig=0; while(len<(lB<<1)) len<<=1,dig++; for(register int i=0;i<len;i++) { a[0][i]=(_cm){(double)(i+1>lA || A[i+1]=='*' ? 0 : A[i+1]-'a'+1)}; b[0][i]=(_cm){(double)(i+1>lB || B[i+1]=='*' ? 0 : B[i+1]-'a'+1)}; _cm_times(a[1][i],a[0][i],a[0][i]),_cm_times(a[2][i],a[1][i],a[0][i]); _cm_times(b[1][i],b[0][i],b[0][i]),_cm_times(b[2][i],b[1][i],b[0][i]); flip[i]=(flip[i>>1]>>1)|((i&1)<<(dig-1)); } for(register int k=0;k<3;k++) { FFT(len,a[k]),FFT(len,b[2-k]); for(register int i=0;i<len;i++) _cm_times(a[k][i],a[k][i],b[2-k][i]); FFT(len,a[k],true); } for(register int i=lA-1;i<lB;i++) if(_abs(a[2][i].a-2*a[1][i].a+a[0][i].a) < eps) printf("%d ",i-lA+2); printf("\n"); return 0; } |