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;
}