BZOJ4259: 残缺的字符串

Posted Star_Feel

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ4259: 残缺的字符串相关的知识,希望对你有一定的参考价值。

【传送门:BZOJ4259&BZOJ4503


简要题意:

  给出两个字符串,第一个串长度为m,第二个串长度为n,字符串中如果有*字符,则代表当前位置可以匹配任何字符

  求出第一个字符串在第二个字串中出现的次数,及出现的位置开头在第二个字符串的位置(从小到大输出)


题解:

  FFT,通配符匹配

  两道题几乎没区别

  对于两个串长度为i,它们的相似程度为$\sum_{j=0}^{i-1}(A[j]-B[j])^2$(A[j]!=‘*‘&&B[j]!=‘*‘)

  把*设为0,则得到$\sum_{j=0}^{i-1}(A[j]-B[j])^2A[j]B[j]$

  显然只有当$\sum_{j=0}^{i-1}(A[j]-B[j])^2A[j]B[j]$为0时,A串和B串才能完全匹配

  那么对于这道题而言,设f(i)为以B的i位置为结尾的长度为n的子串与A串的相似程度

  先将n--,m--(方便写公式),然后在A后面补0

  显然$f(i)=\sum_{j=0}^{m}(A[j]-B[i-m+j])^2A[j]B[i-m+j]$

  我们把A数组翻转,就会得到$f(i)=\sum_{j=0}^{i}(A[j]-B[i-j])^2A[j]B[i-j]$

  然后把这个式子拆开就得到$f(i)=\sum_{j=0}^{i}A[j]^3B[i-j]-2*\sum_{j=0}^{i}A[j]^2B[i-j]^2+\sum_{j=0}^{i}A[j]*B[i-j]^3$

  皆大欢喜,直接三次FFT分别求就可以了


参考代码(一):

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const double PI=acos(-1.0);
struct Complex
{
    double r,i;
    Complex(){}
    Complex(double _r,double _i){r=_r;i=_i;}
    friend Complex operator + (const Complex &x,const Complex &y){return Complex(x.r+y.r,x.i+y.i);}
    friend Complex operator - (const Complex &x,const Complex &y){return Complex(x.r-y.r,x.i-y.i);}
    friend Complex operator * (const Complex &x,const Complex &y){return Complex(x.r*y.r-x.i*y.i,x.r*y.i+x.i*y.r);}
}a[1300000],b[1300000];
int R[1300000];
void fft(Complex *y,int len,int on)
{
    for(int i=0;i<len;i++) if(i<R[i]) swap(y[i],y[R[i]]);
    for(int i=1;i<len;i<<=1)
    {
        Complex wn(cos(PI/i),sin(on*PI/i));
        for(int j=0;j<len;j+=(i<<1))
        {
            Complex w(1,0);
            for(int k=0;k<i;k++,w=w*wn)
            {
                Complex u=y[j+k];
                Complex v=w*y[j+k+i];
                y[j+k]=u+v;
                y[j+k+i]=u-v;
            }
        }
    }
    if(on==-1) for(int i=0;i<=len;i++) y[i].r/=len;
}
void calc(int n,int m)
{
    int L=0;m+=n;
    for(n=1;n<=m;n<<=1) L++;
    memset(R,0,sizeof(R));
    for(int i=0;i<n;i++) R[i]=(R[i>>1]>>1)|(i&1)<<(L-1);
    fft(a,n,1);fft(b,n,1);
    for(int i=0;i<=n;i++) a[i]=a[i]*b[i];
    fft(a,n,-1);
}
char s1[310000],s2[310000];
int A[310000],B[310000];
int q[310000];
double f[310000];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);n--;m--;
    scanf("%s%s",s1,s2);
    for(int i=0;i<=n;i++)
    {
        if(s1[n-i]==*) A[i]=0;
        else A[i]=s1[n-i]-a+1;
    }
    for(int i=0;i<=m;i++)
    {
        if(s2[i]==*) B[i]=0;
        else B[i]=s2[i]-a+1;
    }
    memset(f,0,sizeof(f));
    for(int i=0;i<=n;i++) a[i].r=A[i]*A[i]*A[i];
    for(int i=0;i<=m;i++) b[i].r=B[i];
    calc(n,m);
    for(int i=0;i<=m;i++) f[i]+=a[i].r;
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    for(int i=0;i<=n;i++) a[i].r=A[i]*A[i];
    for(int i=0;i<=m;i++) b[i].r=B[i]*B[i];
    calc(n,m);
    for(int i=0;i<=m;i++) f[i]-=2.0*a[i].r;
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    for(int i=0;i<=n;i++) a[i].r=A[i];
    for(int i=0;i<=m;i++) b[i].r=B[i]*B[i]*B[i];
    calc(n,m);
    for(int i=0;i<=m;i++) f[i]+=a[i].r;
    int cnt=0;
    for(int i=n;i<=m;i++) if(f[i]<0.5) q[++cnt]=i-n;
    printf("%d\n",cnt);
    if(cnt>0)
    {
        for(int i=1;i<cnt;i++) printf("%d ",q[i]+1);
        printf("%d\n",q[cnt]+1);
    }
    return 0;
}

 


参考代码(二):

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const double PI=acos(-1.0);
struct Complex
{
    double r,i;
    Complex(){}
    Complex(double _r,double _i){r=_r;i=_i;}
    friend Complex operator + (const Complex &x,const Complex &y){return Complex(x.r+y.r,x.i+y.i);}
    friend Complex operator - (const Complex &x,const Complex &y){return Complex(x.r-y.r,x.i-y.i);}
    friend Complex operator * (const Complex &x,const Complex &y){return Complex(x.r*y.r-x.i*y.i,x.r*y.i+x.i*y.r);}
}a[1300000],b[1300000];
int R[1300000];
void fft(Complex *y,int len,int on)
{
    for(int i=0;i<len;i++) if(i<R[i]) swap(y[i],y[R[i]]);
    for(int i=1;i<len;i<<=1)
    {
        Complex wn(cos(PI/i),sin(on*PI/i));
        for(int j=0;j<len;j+=(i<<1))
        {
            Complex w(1,0);
            for(int k=0;k<i;k++,w=w*wn)
            {
                Complex u=y[j+k];
                Complex v=w*y[j+k+i];
                y[j+k]=u+v;
                y[j+k+i]=u-v;
            }
        }
    }
    if(on==-1) for(int i=0;i<=len;i++) y[i].r/=len;
}
void calc(int n,int m)
{
    int L=0;m+=n;
    for(n=1;n<=m;n<<=1) L++;
    memset(R,0,sizeof(R));
    for(int i=0;i<n;i++) R[i]=(R[i>>1]>>1)|(i&1)<<(L-1);
    fft(a,n,1);fft(b,n,1);
    for(int i=0;i<=n;i++) a[i]=a[i]*b[i];
    fft(a,n,-1);
}
char s1[310000],s2[310000];
int A[310000],B[310000];
int q[310000];
double f[310000];
int main()
{
    int m,n;
    scanf("%s%s",s1,s2);
    m=strlen(s1);n=strlen(s2);
    m--;n--;
    for(int i=0;i<=m;i++) B[i]=s1[i]-a+1;
    for(int i=0;i<=n;i++)
    {
        if(s2[n-i]==?) A[i]=0;
        else A[i]=s2[n-i]-a+1;
    }
    memset(f,0,sizeof(f));
    for(int i=0;i<=n;i++) a[i].r=A[i]*A[i]*A[i];
    for(int i=0;i<=m;i++) b[i].r=B[i];
    calc(n,m);
    for(int i=0;i<=m;i++) f[i]+=a[i].r;
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    for(int i=0;i<=n;i++) a[i].r=A[i]*A[i];
    for(int i=0;i<=m;i++) b[i].r=B[i]*B[i];
    calc(n,m);
    for(int i=0;i<=m;i++) f[i]-=2.0*a[i].r;
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    for(int i=0;i<=n;i++) a[i].r=A[i];
    for(int i=0;i<=m;i++) b[i].r=B[i]*B[i]*B[i];
    calc(n,m);
    for(int i=0;i<=m;i++) f[i]+=a[i].r;
    int cnt=0;
    for(int i=n;i<=m;i++) if(f[i]<0.5) q[++cnt]=i-n;
    printf("%d\n",cnt);
    if(cnt>0) for(int i=1;i<=cnt;i++) printf("%d\n",q[i]);
    return 0;
}

 

以上是关于BZOJ4259: 残缺的字符串的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ4259: 残缺的字符串

BZOJ4259 残缺的字符串 多项式 FFT

@bzoj - 4259@ 残缺的字符串

bzoj4259: 残缺的字符串

bzoj4259: 残缺的字符串

Bzoj4259 残缺的字符串