• 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
    ",ans[0]);
        for(int i=1;i<=ans[0];++i)printf("%d ",ans[i]);
        return 0;
    } 
  • 相关阅读:
    java设计模式之代理模式 ,以及和java 回调机制的区别
    oracle 安装,启动 ,plsql 连接
    jsp 访问文件夹中的图片,tomcat配置虚拟目录
    最实用解决tomcat startup.bat 一闪而过
    oracle 创建表
    java debug源码完整版
    node.js事件轮询(1)
    markdown命令语法
    mac常用的命令
    node + nginx + mongo搭建负载均衡
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10420583.html
Copyright © 2020-2023  润新知