Luogu4173 残缺的字符串

https://www.luogu.com.cn/problem/P4173

\(NTT\)

按照套路,把模式串\(A\)倒过来(注:一下公式中的\(A\)为已经倒过来的串)

定义\('*'\)值为\(0\),\('a'\cdots 'z'\)值为\(1\cdots 26\)

\(B\)串在\(i\)位置匹配,那么必然有:

\[\sum_{j=0}^{m-1} (A_{m-j-1}-B_{i+j})^2A_{m-j-1}B_{i+j}=0 \]

推式子:

\[(A_{m-j-1}-B_{i+j})^2A_{m-j-1}B_{i+j}\\ =A_{m-j-1}^3B_{i+j}-2A_{m-j-1}^2B_{i+j}^2+A_{m-j-1}B_{i+j}^3 \]

\(NTT+NTT+NTT,Over!\)

T了,时间卡不过去,只好无耻地用Ofast

\(C++ Code:\)

#pragma GCC optimize(Ofast)
#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 12000005
#define p 998244353
#define ll long long
using namespace std;
int m,n,l,s,rev[N];
int ans[N],A[N],B[N];
int Ans,G[2][24],a[N],b[N],c[N],d[N],e[N];
char s1[N],s2[N];
int ksm(int x,int y)
{
    int ans=1;
    while (y)
    {
        if (y & 1)
            ans=(ll)ans*x%p;
        x=(ll)x*x%p;
        y >>=1;
    }
    return ans;
}
#define inv(x) (ksm(x,p-2))
void NTT(int *a,int t)
{
    for (int i=0;i<s;i++)
        if (i < rev[i])
            swap(a[i],a[rev[i]]);
    for (int mid=1,o=1;mid<s;mid <<=1,o++)
        for (int j=0;j<s;j+=(mid << 1))
        {
            int g=1;
            for (int k=0;k<mid;k++,g=(ll)g*G[t][o]%p)
            {
                ll x=a[j+k],y=(ll)g*a[j+k+mid]%p;
                a[j+k]=(x+y)%p;
                a[j+k+mid]=(x-y)%p;
            }
        }
}
void Pre()
{
    G[0][23]=ksm(3,(p-1)/(1 << 23));
    G[1][23]=inv(G[0][23]);
    for (int i=22;i>=1;i--)
    {
        G[0][i]=(ll)G[0][i+1]*G[0][i+1]%p;
        G[1][i]=(ll)G[1][i+1]*G[1][i+1]%p;
    }
}
int main()
{
    Pre();
    scanf("%d%d",&m,&n);
    scanf("%s%s",s1,s2);
    for (int i=0;i<m;i++)
        A[i]=(s1[i]=='*')?0:(s1[i]-'a'+1);
    for (int i=0;i<m/2;i++)
        swap(A[i],A[m-i-1]);
    for (int i=0;i<n;i++)
        B[i]=(s2[i]=='*')?0:(s2[i]-'a'+1);
    l=0,s=1;
    while (s<n+m)
    {
        s <<=1;
        l++;
    }
    ll t=inv(s);
    for (int i=0;i<s;i++)
        rev[i]=(rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
    for (int i=0;i<m;i++)
        a[i]=(ll)A[i]*A[i]*A[i]%p*t%p;
    for (int i=m;i<s;i++)
        a[i]=0;
    for (int i=0;i<n;i++)
        b[i]=B[i];
    for (int i=n;i<s;i++)
        b[i]=0;
    NTT(a,0);
    NTT(b,0);
    for (int i=0;i<s;i++)
        c[i]=(ll)a[i]*b[i]%p;
    NTT(c,1);
    for (int i=0;i<m;i++)
        a[i]=(ll)A[i]*A[i]%p*t%p;
    for (int i=m;i<s;i++)
        a[i]=0;
    for (int i=0;i<n;i++)
        b[i]=B[i]*B[i];
    for (int i=n;i<s;i++)
        b[i]=0;
    NTT(a,0);
    NTT(b,0);
    for (int i=0;i<s;i++)
        d[i]=(ll)a[i]*b[i]%p;
    NTT(d,1);
    for (int i=0;i<m;i++)
        a[i]=(ll)A[i]*t%p;
    for (int i=m;i<s;i++)
        a[i]=0;
    for (int i=0;i<n;i++)
        b[i]=B[i]*B[i]*B[i];
    for (int i=n;i<s;i++)
        b[i]=0;
    NTT(a,0);
    NTT(b,0);
    for (int i=0;i<s;i++)
        e[i]=(ll)a[i]*b[i]%p;
    NTT(e,1);
    for (int i=0;i<n;i++)
    {
        Ans=(((ll)c[i]-(d[i] << 1)+e[i])%p+p)%p;
        if (!Ans&&i-m+1>=0)
            ans[++ans[0]]=i-m+1;
    }
    printf("%d\n",ans[0]);
    for (int i=1;i<=ans[0];i++)
        printf("%d ",ans[i]+1);
    putchar('\n');
    return 0;
}
posted @ 2020-08-01 13:56  GK0328  阅读(73)  评论(0编辑  收藏  举报