CF954I Yet Another String Matching Problem ( FFT )
Description
给出两个字符串S和T
定义两个等长的字符串A和B之间的距离为:
每次操作可以选择两个字符c1和c2,将两个字符串中的所有c1替换为c2,这样将A和B变为相等的最小操作次数。
求S的每个长度为|T|的子串和T之间的距离。
n<=125000,保证S和T只含有小写字母a~f
暴力的话,每个子串用并查集o (n) 的扫一遍的话复杂度是 s × t 的
考虑如何优化
题目的字符集之有6,所以可以考虑在每一块中,枚举的两个字符之间是否在对应位置匹配(这个可以FFT搞了)
若果匹配的话的,再看在当前块内,这两个字符的fa是否是一个
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cmath> 6 #include<algorithm> 7 #include<set> 8 #include<map> 9 #include<vector> 10 #include<queue> 11 using namespace std; 12 #define ll long long 13 #define RG register 14 #define MAX 333333 15 const double Pi=acos(-1); 16 struct Complex{double a,b;}A[MAX],B[MAX],W[MAX]; 17 Complex operator+(Complex a,Complex b){return (Complex){a.a+b.a,a.b+b.b};} 18 Complex operator-(Complex a,Complex b){return (Complex){a.a-b.a,a.b-b.b};} 19 Complex operator*(Complex a,Complex b){return (Complex){a.a*b.a-a.b*b.b,a.a*b.b+a.b*b.a};} 20 int r[MAX],N,n,m,l,eql[MAX][6][6]; 21 char a[MAX],b[MAX]; 22 void FFT(Complex *P,int opt) 23 { 24 for(int i=1;i<N;++i)if(i<r[i])swap(P[i],P[r[i]]); 25 for(int i=1;i<N;i<<=1) 26 for(int p=i<<1,j=0;j<N;j+=p) 27 for(int k=0;k<i;++k) 28 { 29 Complex w=(Complex){W[N/i*k].a,W[N/i*k].b*opt}; 30 Complex X=P[j+k],Y=w*P[i+j+k]; 31 P[j+k]=X+Y;P[i+j+k]=X-Y; 32 } 33 } 34 int f[6]; 35 int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);} 36 int main() 37 { 38 scanf("%s",a);scanf("%s",b); 39 n=strlen(a),m=strlen(b); 40 for(N=1;N<=(n+m);N<<=1)++l; 41 for(int i=0;i<N;++i)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1)); 42 for(int i=1;i<N;i<<=1) 43 for(int k=0;k<i;++k)W[N/i*k]=(Complex){cos(k*Pi/i),sin(k*Pi/i)}; 44 for(int i=0;i<6;++i) 45 for(int j=0;j<6;++j) 46 { 47 for(int k=0;k<N;++k)A[k].a=A[k].b=B[k].a=B[k].b=0; 48 for(int k=0;k<n;++k)A[k].a=(a[k]==i+97); 49 for(int k=0;k<m;++k)B[k].a=(b[m-k-1]==j+97); 50 FFT(A,1);FFT(B,1); 51 for(int k=0;k<N;++k)A[k]=A[k]*B[k]; 52 FFT(A,-1); 53 for(int k=0;k<N;++k)eql[k][i][j]=(int)(A[k].a/N+0.5); 54 } 55 for(int i=m-1;i<n;++i) 56 { 57 for(int j=0;j<6;++j)f[j]=j; 58 59 int ans=0; 60 61 for(int j=0;j<6;++j) 62 for(int k=0;k<6;++k) 63 if(eql[i][j][k]) 64 { 65 if(getf(j) != getf(k)) 66 { 67 ans ++ ; 68 f[getf(j)] = getf(k); 69 } 70 } 71 72 printf("%d ",ans); 73 } 74 puts(""); 75 return 0; 76 }