一道扩展kmp好题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/DT_Kang/article/details/80752506

不是一道扩展kmp模板题。

题意:给定两个字符串A和B,求B在A中出现了几次及每次的位置。两个串均由小写字母组成,但B串有通配符“*”,表示可以匹配任何非空字符。

B在A中出现过,就是B的每一位和A中的连续的一段对应相等。如果我们构造一个多项式:

ci=j=0m1(sin+j+1tj)2·tj

那么如果 ci 等于零,那么也就说明了A串以 i 结束的长度为 m 的串和B串相同。但是发现这个式子不是很好算,我们把B倒过来,那么:
ci=j=0m1(sijtj)2·tj

然后把平方展开,发现可以用FFT啦。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#define cp comp
using namespace std;
struct comp{
    double x,y;
}h1[400010],h2[400010],g1[400010],g2[400010],ans[400010];
const double pi=acos(-1);
double aa[400010],bb[400010];
char s[100010],t[100010];
int rev[400010],len=1,bit,ksj[400010];
inline cp operator + (cp a,cp b)
{
    cp ans;
    ans.x=a.x+b.x;ans.y=a.y+b.y;
    return ans;
}
inline cp operator - (cp a,cp b)
{
    cp ans;
    ans.x=a.x-b.x;ans.y=a.y-b.y;
    return ans;
}
inline cp operator * (cp a,cp b)
{
    cp ans;
    ans.x=a.x*b.x-a.y*b.y;ans.y=a.x*b.y+a.y*b.x;
    return ans;
}
inline void FFT(cp *a,int t)
{
    for(int i=0;i<len;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
    for(int step=1;step<len;step<<=1)
    {
        cp wn={cos(2*pi/step/2),sin(2*pi*t/step/2)};
        for(int j=0;j<len;j+=(step<<1))
        {
            cp wnk={1,0};
            for(int k=j;k<j+step;k++)
            {
                cp x=a[k],y=wnk*a[k+step];
                a[k]=x+y,a[k+step]=x-y;
                wnk=wnk*wn;
            }
        }
    }
    if(t==-1) for(int i=0;i<len;i++) a[i].x/=len;
}
int main()
{
    scanf("%s%s",s,t);
    double tmp=0;
    int n=strlen(s),m=strlen(t);
    while(len<(n+m)) len<<=1,bit++;
    for(int i=0;i<=len;i++)
        rev[i]=(rev[i>>1]>>1)|((i&1)<<bit-1);
    for(int i=0;i<n;i++) aa[i]=s[i]-'a'+1;
    for(int i=0;i<m;i++) if(t[i]=='*') bb[m-i-1]=0; else bb[m-i-1]=t[i]-'a'+1;
    for(int i=0;i<n;i++) h2[i].x=aa[i]*aa[i],h1[i].x=2*aa[i];
    for(int i=0;i<m;i++) g1[i].x=bb[i],g2[i].x=bb[i]*bb[i],tmp+=bb[i]*bb[i]*bb[i];
    FFT(h1,1),FFT(h2,1),FFT(g1,1),FFT(g2,1);
    for(int i=0;i<len;i++) ans[i]=(h2[i]*g1[i])-(h1[i]*g2[i]);
    FFT(ans,-1);
    int cnt=0;
    for(int i=0;i<len;i++) if(floor(ans[i].x+0.5+tmp)==0) ksj[++cnt]=i-m+1;
    cout<<cnt<<endl;
    for(int i=1;i<=cnt;i++) cout<<ksj[i]<<' ';
    return 0;
}
阅读更多
换一批

没有更多推荐了,返回首页