1. 程式人生 > >bzoj 4259 4259: 殘缺的字串【FFT】

bzoj 4259 4259: 殘缺的字串【FFT】

和bzoj 4503 https://www.cnblogs.com/lokiii/p/10032311.html 差不多,就是再乘上一個原串字元
有點卡常,先在點值下算最後一起IDFT

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int N=1100005;
int n,m,bt,lm,re[N],tot;
long long x[N],y[N];
double sm;
char s[N],t[N];
struct cd
{
    double a,b;
    cd(double A=0,double B=0)
    {
        a=A,b=B;
    }
    cd operator + (const cd &x) const
    {
        return cd(a+x.a,b+x.b);
    }
    cd operator - (const cd &x) const
    {
        return cd(a-x.a,b-x.b);
    }
    cd operator * (const cd &x) const
    {
        return cd(a*x.a-b*x.b,a*x.b+b*x.a);
    }
}a[N],b[N],c[N];
void dft(cd a[],int f)
{
    for(int i=0;i<lm;i++)
        if(i<re[i])
            swap(a[i],a[re[i]]);
    for(int i=1;i<lm;i<<=1)
    {
        cd wi=cd(cos(M_PI/i),f*sin(M_PI/i));
        for(int k=0;k<lm;k+=(i<<1))
        {
            cd w=cd(1,0),x,y;
            for(int j=0;j<i;j++)
            {
                x=a[j+k],y=w*a[i+j+k];
                a[j+k]=x+y,a[i+j+k]=x-y;
                w=w*wi;
            }
        }
    }
    if(f==-1)
        for(int i=0;i<lm;i++)
            a[i].a/=lm;
}
int main()
{
    scanf("%d%d%s%s",&n,&m,t,s);
    for(int i=0,j=n-1;i<j;i++,j--)
        swap(t[i],t[j]);
    for(int i=0;i<n;i++)
        x[i]=(t[i]=='*')?0:t[i]-'a'+1,a[i].a=x[i]*x[i]*x[i];
    for(int i=0;i<m;i++)
        y[i]=(s[i]=='*')?0:s[i]-'a'+1,b[i].a=y[i];
    for(bt=0;(1<<bt)<=n+m;bt++);
    lm=1<<bt;
    for(int i=0;i<lm;i++)
        re[i]=(re[i>>1]>>1)|((i&1)<<(bt-1));
    dft(a,1),dft(b,1);
    for(int i=0;i<lm;i++)
        c[i]=c[i]+a[i]*b[i];
    for(int i=0;i<lm;i++)
        a[i]=cd(x[i],0),b[i]=cd(y[i]*y[i]*y[i],0);
    dft(a,1),dft(b,1);
    for(int i=0;i<lm;i++)
        c[i]=c[i]+a[i]*b[i];
    for(int i=0;i<lm;i++)
        a[i]=cd(x[i]*x[i],0),b[i]=cd(y[i]*y[i],0);
    dft(a,1),dft(b,1);
    for(int i=0;i<lm;i++)
        c[i]=c[i]-a[i]*b[i]*cd(2,0);
    dft(c,-1);
    for(int i=n-1;i<m;i++)
        if((int)(c[i].a+0.5)==0)
            tot++;
    printf("%d\n",tot);
    for(int i=n-1;i<m;i++)
        if((int)(c[i].a+0.5)==0)
            printf("%d ",i-n+2);
    return 0;
}