1. 程式人生 > >BZOJ4259殘缺的字符串

BZOJ4259殘缺的字符串

algo 發現 -m 包含 htm names pan line inline

題目描述

很久很久以前,在你剛剛學習字符串匹配的時候,有兩個僅包含小寫字母的字符串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; }

BZOJ4259殘缺的字符串