• bzoj4259 残缺的字符串


    题目描述

    给定 $S,T$ ,其中 $|T|<|S|$ ,问 $T$ 在 $S$ 中出现了几次, $*$ 可以充当任何字母

    数据范围

    $|T|<|S| le 3 imes 10^5$

    题解

    如果没有 $*$ 的话,那可以想一种构造方法,使我们快速判定 $S$ 中的某个子串是不是和 $T$ 相同。

    假设 $S$ 从下标 $k$ 开始,也就是快速判断 $sum [S_{k+i-1}=T_i]$ 是不是等于 $|T|$ 。

    那我们可以换种思路,如果 $S_{k+i-1}=T_i$ ,那么 $S_{k-i+1}-T_i=0$ 。

    所以我们可以判断 $sum (S_{k+i-1}-T_i)^2$ 是不是等于 $0$ 。

    然后我们发现他们下标的差是固定的,所以我们可以把 $T$ 翻转,然后把式子展开,我们就得到了卷积的形式。

    现在有 $*$ 的限制,那只需要让是 $*$ 的那一位的权值设成 $0$ ,我们判断 $sum (S_{k+i-1}-T_{|T|-i+1})^2 imes S_{k+i-1} imes T_{|T|-i+1}$ 是不是等于$0$ 即可。

    效率: $O(nlogn)$

    代码

    #include <bits/stdc++.h>
    #define db double
    using namespace std;
    const int N=12e5+5;
    const db PI=acos(-1);
    char S[N],T[N];
    int n,m,t=1,p,r[N],f[N],s;
    struct O{db r,i;}a[N],b[N],c[N],d[N],e[N],h[N];
    O operator + (O A,O B){
        return (O){A.r+B.r,A.i+B.i};
    }
    O operator - (O A,O B){
        return (O){A.r-B.r,A.i-B.i};
    }
    O operator * (O A,O B){
        return (O){A.r*B.r-A.i*B.i,A.r*B.i+A.i*B.r};
    }
    void FFt(O *g,int o){
        for (int i=0;i<t;i++)
            if (i<r[i]) swap(g[i],g[r[i]]);
        for (int i=1;i<t;i<<=1){
            O wn=(O){cos(PI/i),sin(PI/i)*o};
            for (int j=0;j<t;j+=(i<<1)){
                O w=(O){1,0},x,y;
                for (int k=0;k<i;k++,w=w*wn)
                    x=g[j+k],y=g[i+j+k]*w,
                    g[j+k]=x+y,g[i+j+k]=x-y;
            }
        }
        if (!~o) for (int i=0;i<t;i++) g[i].r/=t;
    }
    int main(){
        scanf("%d%d%s%s",&m,&n,T,S);
        for (;t<n+m;t<<=1,p++);
        for (int i=0;i<t;i++)
            r[i]=(r[i>>1]>>1)|((i&1)<<(p-1));
        for (int x,i=0;i<n;i++) if (S[i]!='*')
            x=S[i]-96,a[i].r=x*x*x,b[i].r=2*x*x,e[i].r=x;
        for (int x,i=0;i<m;i++) if (T[m-i-1]!='*')
            x=T[m-i-1]-96,c[i].r=x,d[i].r=x*x,h[i].r=x*x*x;
        FFt(a,1);FFt(b,1);FFt(c,1);FFt(d,1);FFt(e,1);FFt(h,1);
        for (int i=0;i<t;i++)
            a[i]=a[i]*c[i]-b[i]*d[i]+e[i]*h[i];FFt(a,-1);
        for (int i=m-1;i<n;i++)
            if ((int)(a[i].r+.5)==0)
                f[++s]=i-m+1;printf("%d
    ",s);
        for (int i=1;i<=s;i++)
            printf("%d",f[i]+1),putchar(i<s?' ':'
    ');
        return 0;
    }
  • 相关阅读:
    HCL AppScan Standard 9.0.3.13
    appscan 9.0.3.12 版本下载--补丁验证---win10 验证OK
    appscan 9.0.3.10 版本及补丁下载
    appscan 历史版本下载
    Python 批量文件下载
    广告URL
    Linux 修改hostname几种方式
    Kali系统 metasploit 使用教程
    Metasploit
    NIKTO
  • 原文地址:https://www.cnblogs.com/xjqxjq/p/12236703.html
Copyright © 2020-2023  润新知