zoukankan      html  css  js  c++  java
  • BZOJ#4503. 两个串


    4503: 两个串

    Time Limit: 20 Sec  Memory Limit: 256 MB
    Submit: 1128  Solved: 457

    Description

    兔子们在玩两个串的游戏。给定两个字符串S和T,兔子们想知道T在S中出现了几次,
    分别在哪些位置出现。注意T中可能有“?”字符,这个字符可以匹配任何字符。

    Input

    两行两个字符串,分别代表S和T

    Output

    第一行一个正整数k,表示T在S中出现了几次
    接下来k行正整数,分别代表T每次在S中出现的开始位置。按照从小到大的顺序输出,S下标从0开始。

    Sample Input

    bbabaababaaaaabaaaaaaaabaaabbbabaaabbabaabbbbabbbbbbabbaabbbababababbbbbbaaabaaabbbbbaabbbaabbbbabab
    a?aba?abba

    Sample Output

    0

    HINT

    S 长度不超过 10^5, T 长度不会超过 S。 S 中只包含小写字母, T中只包含小写字母和“?”
     

    Problem:

    给定一个文本串(只包含a,b)和一个匹配串,匹配串中会有通用符(与任意字符都匹配),问文本串中有多少和匹配串相同的子串



    Solution:
    先看没有通用符怎么判断匹配
    怎么判断一个字符匹配?
    它们相等就匹配
    怎么判断一个字符串匹配?
    它们中每个对应的字符匹配就匹配
    那么在这里可得一个式子:
    Σ(a[i]-b[i])=0
    可是会出现前面与后面刚好相加为0的情况
    那么再改进一下:
    Σ[(a[i]-b[i])^2]=0

    如果有通用符怎么办?
    Σ[b[i]*(a[i]-b[i])^2]=0 (b为匹配串,赋通用符为0,那么如果它为通用符,或者和a相等就匹配)

    再化解一下式子:
    ans=Σb[i]*(a[i]*a[i]-2*a[i]*b[i]+b[i]*b[i]
    =Σa[i]*a[i]*b[i]-Σ2*a[i]*b[i]*b[i]+Σb[i]*b[i]*b[i]

    式子解决了,我们怎么求?
    看这个形式,如果我们把b反一下
    我们就可以用卷积求得

    可能没想清楚的同学会问,怎么保证卷积算出来的刚好就是一段连续的len2长度的子串
    那么可以想一下,举个例子:
    a=0 1 2 3 4 5 /b=0 1 2
    当正在找以5为结尾的子串时
    我们的卷积算的是Σa[i]+b[j](i+j==5)
    我们b的j只会有0,1,2
    那么我们的a只会选到相加等于5的编号的值,也就是5,4,3
    可以看到我们刚好就是选到这个子串

    ok!


     附上代码:

    #include<bits/stdc++.h>
    using namespace std;
    const double pi=acos(-1);
    const int N=880010;
    char s1[N],s2[N];
    int n;
    
    struct Complex
    {
        double x,i;
        Complex(){}
        Complex(double a,double b) {x=a;i=b;}
    }A[N],B[N],C[N];
    Complex operator + (Complex a,Complex b) {return Complex(a.x+b.x,a.i+b.i);}
    Complex operator - (Complex a,Complex b) {return Complex(a.x-b.x,a.i-b.i);}
    Complex operator * (Complex a,Complex b) {return Complex(a.x*b.x-a.i*b.i,a.x*b.i+a.i*b.x);}
    
    
    int rev[N];
    void FFT(Complex *a,int t)
    {
        for(int i=0;i<n;i++) if(rev[i]>i) swap(a[i],a[rev[i]]);
        for(int i=1;i<n;i<<=1)
        {
            Complex wn(cos(2*pi/(i<<1)),t*sin(2*pi/(i<<1)));
            for(int j=0;j<n;j+=(i<<1))
            {
                Complex w(1,0),t0,t1;
                for(int k=0;k<i;k++) 
                {
                    t0=a[j+k];t1=w*a[i+j+k];
                    a[j+k]=t0+t1;
                    a[i+j+k]=t0-t1;
                    w=w*wn;
                }
            }
        }
    }
    
    int ans[N],cnt;
    int a[N],b[N];
    int main()
    {
        freopen("a.in","r",stdin);
        scanf("%s%s",s1,s2);
        int len1=strlen(s1),len2=strlen(s2);
        n=1;
        
        int len=0;
        while(n<len1*2) n<<=1,len++;
        rev[0]=0;for(int i=1;i<n;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(len-1));
        
        for(int i=0;i<len1;i++) a[i]=s1[i]-'a'+1;
        for(int i=0;i<len2;i++) b[len2-i-1]=s2[i]=='?'?0:s2[i]-'a'+1;
        for(int i=0;i<n;i++) A[i]=Complex(b[i]*b[i]*b[i],0),B[i]=Complex(1,0);
        FFT(A,1);FFT(B,1);
        
        for(int i=0;i<n;i++) C[i]=A[i]*B[i];
        for(int i=0;i<n;i++) A[i]=Complex(2*a[i],0),B[i]=Complex(b[i]*b[i],0);
        FFT(A,1);FFT(B,1);
        for(int i=0;i<n;i++) C[i]=C[i]-A[i]*B[i];
        for(int i=0;i<n;i++) A[i]=Complex(a[i]*a[i],0),B[i]=Complex(b[i],0);
        FFT(A,1);FFT(B,1);
        for(int i=0;i<n;i++) C[i]=C[i]+A[i]*B[i];
        FFT(C,-1);
        
        for(int i=0;i<n;i++) C[i].x=(int)(C[i].x/n+0.5);
        for(int i=len2-1;i<len1;i++) if(C[i].x==0) ans[++cnt]=i-len2+1;
        printf("%d
    ",cnt);
        for(int i=1;i<=cnt;i++) printf("%d
    ",ans[i]);
        return 0;
    }
    View Code

  • 相关阅读:
    页面静态化3 --- 伪静态技术
    9.14[XJOI] NOIP训练33
    9.13[XJOI] NOIP训练32
    Hello world!
    BZOJ-1853: [Scoi2010]幸运数字 (容斥原理)
    luogu1983[NOIP2013pjT4] 车站分级(拓扑排序)
    luogu1113 杂物 (拓扑排序)
    POJ-1094 Sorting It All Out && luogu1347 排序 (拓扑排序)
    BZOJ-1965: [Ahoi2005]SHUFFLE 洗牌 (快速幂+乘转加)
    BZOJ-2705: [SDOI2012]Longge的问题 (欧拉函数)
  • 原文地址:https://www.cnblogs.com/Heey/p/9058204.html
Copyright © 2011-2022 走看看