BZOJ4259:残缺的字符串——题解

https://www.lydsy.com/JudgeOnline/problem.php?id=4259

很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n。可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺。
你想对这两个串重新进行匹配,其中A为模板串,那么现在问题来了,请回答,对于B的每一个位置i,从这个位置开始连续m个字符形成的子串是否可能与A串完全匹配?

跟随胡神犇的步伐先把前置技能学了。

参考:https://www.cnblogs.com/clrs97/p/4814499.html

kmp是不行的,而作为一道套路题,我们有一定的套路:暴力匹配!

先默认字符串是以0开头的,方便我们后来FFT。

设dis(A,B)=(A-B)*[A!='*']*[B!='*']表示了AB字符是否相等,如果相等则答案为0。

于是我们把*字符看做0,则直接变成dis(A,B)=(A-B)AB。

设f[i]为B串以i为终点,往前与A匹配是否能匹配上。

显然就是dis累加的过程,只要最终f[i]=0就说明i-n+2是一个合法解。

然后你就会发现这个dis累加拆开之后很像卷积啊。

于是把A数组倒过来然后后面补齐0(即*字符),你就会发现实际上这就是三个卷积。

于是我们(不)愉快的写了个FFT并且AC。

(式子推导就看参考吧……心情不好不想写数学公式)

#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef double dl;
const dl pi=acos(-1.0);
const dl eps=0.5;
const int N=2e6+5;
struct complex{
    dl x,y;
    complex(dl xx=0.0,dl yy=0.0){
    x=xx;y=yy;
    }
    complex operator +(const complex &b)const{
    return complex(x+b.x,y+b.y);
    }
    complex operator -(const complex &b)const{
    return complex(x-b.x,y-b.y);
    }
    complex operator *(const complex &b)const{
    return complex(x*b.x-y*b.y,x*b.y+y*b.x);
    }
};
void FFT(complex a[],int n,int on){
    for(int i=1,j=n>>1;i<n-1;i++){
    if(i<j)swap(a[i],a[j]);
    int k=n>>1;
    while(j>=k){j-=k;k>>=1;}
    if(j<k)j+=k;
    }
    for(int i=2;i<=n;i<<=1){
    complex res(cos(-on*2*pi/i),sin(-on*2*pi/i));
    for(int j=0;j<n;j+=i){
        complex w(1,0);
        for(int k=j;k<j+i/2;k++){
        complex u=a[k],t=w*a[k+i/2];
        a[k]=u+t;a[k+i/2]=u-t;
        w=w*res;
        }
    }
    }
    if(on==-1)
    for(int i=0;i<n;i++)a[i].x/=n;
}
int n,m,a[N],b[N];
complex f[N],A[N],B[N];
char s1[N],s2[N];
int main(){
    scanf("%d%d%s%s",&n,&m,s1,s2);
    for(int i=0,j=n-1;i<j;i++,j--)swap(s1[i],s1[j]);
    for(int i=0;i<n;i++){
    if(s1[i]!='*')a[i]=s1[i]-'a'+1;
    else a[i]=0;
    }
    for(int i=0;i<m;i++){
    if(s2[i]!='*')b[i]=s2[i]-'a'+1;
    else b[i]=0;
    }
    int len=1;
    while(len<m)len<<=1;

    for(int i=0;i<len;i++)
    A[i]=complex(a[i]*a[i]*a[i],0),B[i]=complex(b[i],0);
    FFT(A,len,1);FFT(B,len,1);
    for(int i=0;i<len;i++)f[i]=f[i]+A[i]*B[i];
    
    for(int i=0;i<len;i++)
    A[i]=complex(a[i]*a[i],0),B[i]=complex(b[i]*b[i],0);
    FFT(A,len,1);FFT(B,len,1);
    for(int i=0;i<len;i++)f[i]=f[i]-A[i]*B[i]*complex(2,0);

    for(int i=0;i<len;i++)
    A[i]=complex(a[i],0),B[i]=complex(b[i]*b[i]*b[i],0);
    FFT(A,len,1);FFT(B,len,1);
    for(int i=0;i<len;i++)f[i]=f[i]+A[i]*B[i];

    FFT(f,len,-1);
    int ans=0;
    for(int i=n-1;i<m;i++)if(f[i].x<eps)ans++;
    printf("%d\n",ans);
    if(ans){
    for(int i=n-1;i<m;i++)if(f[i].x<eps)printf("%d ",i-n+2);
    puts("");
    }
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

 +本文作者:luyouqi233。               +

 +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2018-06-10 10:32  luyouqi233  阅读(258)  评论(0编辑  收藏  举报