zoukankan      html  css  js  c++  java
  • 【BZOJ4259】残缺的字符串

    题面

    1684 -- 【BZOJ4259】残缺的字符串

    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 7

    a*b

    aebr*ob

    Sample Output

    2

    1 5

    题目分析

    法一:

    我们可以参考【BZOJ3160】万径人踪灭的做法,相当于求(26)组FFT,若和==长度即可。

    然而,这样做相当于(O(26nlog n)),无法在1s内完成。


    法二:

    还是考虑FFT,我们能否改变状态,让他用更少的次数求出答案?

    如果(a_i,b_j)要配上,要么(a_i==b_j),要么(a_i==*||b_j==*)

    (a_i==b_j),有((a_i-b_j))=0,

    而当(a_i==*||b_j==*​),我们可以把(*​)的值设为(0​),所以有(displaystylesum_{i=1}^m(a_i-b_{j+i})cdot a_icdot b_{j+i}==0​)

    但是,我们要考虑,(a_i-b_{j+i})可正可负,

    为了防止恰好和为(0),我们写作(displaystylesum_{i=1}^m(a_i-b_{j+i})^2cdot a_icdot b_{j+i}==0)

    (b)反转,可以写作与法一相似的卷积的形式,然后分别求解拼起来即可。

    代码实现

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<cstdio>
    #include<iomanip>
    #include<cstdlib>
    #include<complex>
    #define MAXN 0x7fffffff
    typedef long long LL;
    const int N=1100005;
    using namespace std;
    inline int Getint(){register int x=0,f=1;register char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}return x*f;}
    typedef complex<double>Z;
    const double pi=M_PI;
    void FFT(Z *a,int x,int K){
    	static int rev[N],lst;
    	int n=1<<x;
    	if(n!=lst){
    		for(int i=0;i<n;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<x-1);
    		lst=n;
    	}
    	for(int i=0;i<n;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
    	for(int i=1;i<n;i<<=1){
    		int tmp=i<<1;
    		Z wn(cos(pi/i),sin(pi*K/i));
    		for(int j=0;j<n;j+=tmp){
    			Z w(1,0);
    			for(int k=0;k<i;k++,w=w*wn){
    				Z x=a[j+k],y=w*a[i+j+k];
    				a[j+k]=x+y;a[i+j+k]=x-y;
    			}
    		}
    	}
    	if(K==-1)for(int i=0;i<n;i++)a[i]/=n;
    }
    Z a[3][N],b[3][N],ans[N];
    char A[N],B[N];
    LL Get(Z x){return (LL)(x.real()+0.5);}
    int st[N],top;
    int main(){
    	int m=Getint(),n=Getint();
    	scanf("%s%s",A+1,B+1);
    	reverse(A+1,A+1+m);
    	for(int i=1;i<=m;i++){
    		int x=(isalpha(A[i])?(A[i]-'a'+1):0);
    		a[0][i].real()=x,a[1][i].real()=x*x,a[2][i].real()=x*x*x;
    	}
    	for(int i=1;i<=n;i++){
    		int x=(isalpha(B[i])?(B[i]-'a'+1):0);
    		b[0][i].real()=x,b[1][i].real()=x*x,b[2][i].real()=x*x*x;
    	}
    	
    	int x=ceil(log2(m+n+3));
    	FFT(a[0],x,1),FFT(a[1],x,1),FFT(a[2],x,1);
    	FFT(b[0],x,1),FFT(b[1],x,1),FFT(b[2],x,1);
    	for(int i=0;i<(1<<x);i++)
    		ans[i]=a[0][i]*b[2][i]+a[2][i]*b[0][i]-Z(2,0)*a[1][i]*b[1][i];
    	FFT(ans,x,-1);
    	
    	for(int i=m+1;i<=n+1;i++)if(!Get(ans[i]))st[++top]=i-m;
    	cout<<top<<'
    ';
    	for(int i=1;i<=top;i++)cout<<st[i]<<' ';
    	return 0;
    }
    
    
  • 相关阅读:
    Maven Build Alfresco Solr
    Docker Error response from daemon: manifest for alfresco/alfresco-search-services:latest not found: manifest unknown: manifest unknown
    Salesforce & Alfresco 数据权限机制
    Code Review & CodeFlow | Automated Code Review Tool
    An online request replication tool,session-replay
    低代码开发平台
    架构师成长系列 | 云原生时代的 DevOps 之道
    阿里专有云项目体验
    回顾《人月神话》,承认无知。
    Java应用调试利器——BTrace
  • 原文地址:https://www.cnblogs.com/Emiya-wjk/p/10031586.html
Copyright © 2011-2022 走看看