BZOJ4259残缺的字符串

题目描述

很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n。可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺。

你想对这两个串重新进行匹配,其中A为模板串,那么现在问题来了,请回答,对于B的每一个位置i,从这个位置开始连续m个字符形成的子串是否可能与A串完全匹配?

题解

带通配符的字符串匹配问题。

我们先把通配符设为0,考虑如果匹配串中的一段和模式串完全匹配,那么必然满足∑(a[i]-b[i])^2*a[i]*b[i]=0。

很容易发现这是个卷积,那么把任意一个串倒过来FFT一下就好了。

这题还卡我精度。。。

代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define N 600002
#define double long double
using namespace std;
typedef long long ll;
int l,L,n,m,rev[N],ans[N];
char s1[N],s2[N];
const double pai=acos(-1.0);
struct fs{
    double x,y;
    fs(double xx=0,double yy=0){x=xx;y=yy;}
    fs operator +(const fs &b)const{return fs{x+b.x,y+b.y};}
    fs operator -(const fs &b)const{return fs{x-b.x,y-b.y};}
    fs operator *(const fs &b)const{return fs{x*b.x-y*b.y,x*b.y+y*b.x};}
}a[N],b[N],c[N],d[N],e[N];
inline void FFT(fs *a,int tag){
    for(int i=1;i<l;++i)if(i>rev[i])swap(a[i],a[rev[i]]);
    for(int i=1;i<l;i<<=1){
        fs wn(cos(pai/i),tag*sin(pai/i));
        for(int j=0;j<l;j+=(i<<1)){
            fs w(1,0);
            for(int k=0;k<i;++k,w=w*wn){
                fs x=a[j+k],y=a[i+j+k]*w;
                a[j+k]=x+y;a[i+j+k]=x-y;
            }
        }
    }
}
int main(){
    scanf("%d%d",&m,&n);
    l=1;L=0;
    while(l<n)l<<=1,L++;
    for(int i=1;i<l;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));
    scanf("%s%s",s2,s1);
    for(int i=0;i<n;++i)if(s1[i]=='*')s1[i]=0;else s1[i]-='A';
    for(int i=0;i<m;++i)if(s2[i]=='*')s2[i]=0;else s2[i]-='A';
    reverse(s2,s2+m);
    for(int i=0;i<n;++i)a[i].x=1ll*s1[i]*s1[i]*s1[i];
    for(int i=0;i<m;++i)b[i].x=s2[i];
    FFT(a,1);FFT(b,1);
    for(int i=0;i<l;++i)c[i]=a[i]*b[i];
    FFT(c,-1);
    for(int i=0;i<l;++i)c[i].x=(ll)(c[i].x/l+0.4);
    memset(a,0,sizeof(a));memset(b,0,sizeof(b));
    for(int i=0;i<n;++i)a[i].x=s1[i]*s1[i];
    for(int i=0;i<m;++i)b[i].x=s2[i]*s2[i];
    FFT(a,1);FFT(b,1);
    for(int i=0;i<l;++i)d[i]=a[i]*b[i]*fs(2,0);
    FFT(d,-1);
    for(int i=0;i<l;++i)d[i].x=(ll)(d[i].x/l+0.4);
    memset(a,0,sizeof(a));memset(b,0,sizeof(b));
    for(int i=0;i<n;++i)a[i].x=s1[i];
    for(int i=0;i<m;++i)b[i].x=1ll*s2[i]*s2[i]*s2[i];
    FFT(a,1);FFT(b,1);
    for(int i=0;i<l;++i)e[i]=a[i]*b[i];
    FFT(e,-1);
    for(int i=0;i<l;++i)e[i].x=(ll)(e[i].x/l+0.4);
    for(int i=m-1;i<n;++i)if(c[i].x+e[i].x-d[i].x==0)ans[++ans[0]]=i-m+2;
    printf("%d\n",ans[0]);
    for(int i=1;i<=ans[0];++i)printf("%d ",ans[i]);
    return 0;
} 
posted @ 2019-02-22 20:40  comld  阅读(167)  评论(0编辑  收藏  举报