考虑如何用多项式乘法匹配字符串
设 s s s串长 n n n, t t t串长 m m m,下标从零开始
把字母转化为 [ 1 , 26 ] [1,26] [1,26]的数字,数组分别为 f , g f,g f,g
定义 a n s [ x ] = 0 ans[x]=0 ans[x]=0表示 s s s串的 [ x , x + m − 1 ] [x,x+m-1] [x,x+m−1]和 t t t串匹配
那么如果 a n s [ x ] = ∑ i = 0 m − 1 ( f [ x + i ] − g [ i ] ) = 0 ans[x]=\sum\limits_{i=0}^{m-1}(f[x+i]-g[i])=0 ans[x]=i=0∑m−1(f[x+i]−g[i])=0说明是匹配的
等等!!不太对!!
因为这样 a b ab ab和 b a ba ba也是相互匹配的,因为正负抵消变成了零
为了消除正负号的影响,我们平方一下
a n s [ x ] = ∑ i = 0 m − 1 ( f [ x + i ] − g [ i ] ) 2 ans[x]=\sum\limits_{i=0}^{m-1}(f[x+i]-g[i])^2 ans[x]=i=0∑m−1(f[x+i]−g[i])2
= ∑ i = 0 m − 1 f [ x + i ] 2 + ∑ i = 0 m − 1 g [ i ] 2 − 2 ∑ i = 0 m − 1 f [ x + i ] ∗ g [ i ] =\sum\limits_{i=0}^{m-1}f[x+i]^2+\sum\limits_{i=0}^{m-1}g[i]^2-2\sum\limits_{i=0}^{m-1}f[x+i]*g[i] =i=0∑m−1f[x+i]2+i=0∑m−1g[i]2−2i=0∑m−1f[x+i]∗g[i]
第一项可以前缀和预处理,第二项是常数直接暴力,第三项似乎是一个卷积的形式
我们把 g g g反转记作 G [ i ] = g [ m − 1 − i ] G[i]=g[m-1-i] G[i]=g[m−1−i]
那么 ∑ i = 0 m − 1 f [ x + i ] ∗ G [ m − 1 − i ] \sum\limits_{i=0}^{m-1}f[x+i]*G[m-1-i] i=0∑m−1f[x+i]∗G[m−1−i]
发现 ( x + i ) + ( m − 1 − i ) = m − 1 + x (x+i)+(m-1-i)=m-1+x (x+i)+(m−1−i)=m−1+x是定值
令 e = m + x − 1 e=m+x-1 e=m+x−1
所以可以改写成 ∑ i = 0 e f [ i ] ∗ G [ e − i ] \sum\limits_{i=0}^{e}f[i]*G[e-i] i=0∑ef[i]∗G[e−i]
所以可以得出
a n s [ x ] = ∑ i = 0 m − 1 g [ i ] 2 + ∑ i = 0 m − 1 f [ x + i ] 2 + A [ x + m − 1 ] ans[x]=\sum\limits_{i=0}^{m-1}g[i]^2+\sum\limits_{i=0}^{m-1}f[x+i]^2+A[x+m-1] ans[x]=i=0∑m−1g[i]2+i=0∑m−1f[x+i]2+A[x+m−1]
其中 A [ i ] A[i] A[i]是卷积的第 i i i项
回到这题,因为有通配符的存在,所以我们需要给匹配规则改一下
也就是令通配符位置为 0 0 0
a n s [ x ] = ∑ i = 0 m − 1 ( f [ x + i ] − g [ i ] ) 2 ∗ f [ x + i ] ∗ g [ i ] ans[x]=\sum\limits_{i=0}^{m-1}(f[x+i]-g[i])^2*f[x+i]*g[i] ans[x]=i=0∑m−1(f[x+i]−g[i])2∗f[x+i]∗g[i]
展开可以得到
a n s [ x ] = ∑ i = 0 m − 1 f [ x + i ] 3 ∗ g [ i ] + ∑ i = 0 m − 1 g [ i ] 3 ∗ f [ x + i ] − 2 ∑ i = 0 m − 1 g i 2 f [ x + i ] 2 ans[x]=\sum\limits_{i=0}^{m-1}f[x+i]^3*g[i]+\sum\limits_{i=0}^{m-1}g[i]^3*f[x+i]-2\sum\limits_{i=0}^{m-1}g_i^2f[x+i]^2 ans[x]=i=0∑m−1f[x+i]3∗g[i]+i=0∑m−1g[i]3∗f[x+i]−2i=0∑m−1gi2f[x+i]2
我们还是令 G [ i ] = g [ m − 1 − i ] G[i]=g[m-1-i] G[i]=g[m−1−i]
a n s [ x ] = ∑ i = 0 m − 1 f [ x + i ] 3 ∗ G [ m − 1 − i ] + ∑ i = 0 m − 1 G [ m − 1 − i ] 3 ∗ f [ x + i ] − 2 ∑ i = 0 m − 1 G [ m − 1 − i ] 2 f [ x + i ] 2 ans[x]=\sum\limits_{i=0}^{m-1}f[x+i]^3*G[m-1-i]+\sum\limits_{i=0}^{m-1}G[m-1 -i]^3*f[x+i]-2\sum\limits_{i=0}^{m-1}G[m-1-i]^2f[x+i]^2 ans[x]=i=0∑m−1f[x+i]3∗G[m−1−i]+i=0∑m−1G[m−1−i]3∗f[x+i]−2i=0∑m−1G[m−1−i]2f[x+i]2
我们令 e = m − 1 + x e=m-1+x e=m−1+x
a n s [ x ] = ∑ i = 0 e f [ i ] 3 ∗ G [ e − i ] + ∑ i = 0 e G [ e − i ] 3 ∗ f [ i ] − 2 ∑ i = 0 e G [ e − i ] 2 f [ i ] 2 ans[x]=\sum\limits_{i=0}^{e}f[i]^3*G[e-i]+\sum\limits_{i=0}^{e}G[e-i]^3*f[i]-2\sum\limits_{i=0}^{e}G[e-i]^2f[i]^2 ans[x]=i=0∑ef[i]3∗G[e−i]+i=0∑eG[e−i]3∗f[i]−2i=0∑eG[e−i]2f[i]2
所以 a n s [ x ] ans[x] ans[x]就是所有卷积的第 m − 1 + x m-1+x m−1+x项
于是可以写出下面的代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 9e6+10;
const int mod = 998244353,G=3,GI = 332748118;
int r[maxn],f[maxn],g[maxn],ans[maxn],n,m;
char s[maxn],t[maxn];
int quick(int x,int n)
{
int ans = 1;
for( ; n ; n>>=1,x=1ll*x*x%mod )
if( n&1 ) ans = 1ll*ans*x%mod;
return ans;
}
void NTT(int *a,int limit,int type)
{
for(int i=0;i<limit;i++) if( i<r[i] ) swap(a[i],a[r[i]]);
for(int mid = 1;mid<limit;mid<<=1)
{
int wn = quick( (type==1)?G:GI,(mod-1)/(mid<<1));
for(int R=mid<<1,i=0;i<limit;i+=R)
for(int k=0,w=1;k<mid;k++,w=1ll*w*wn%mod)
{
int x = a[i+k], y = 1ll*w*a[i+k+mid]%mod;
a[i+k] = (1ll*x+y)%mod, a[i+k+mid] = (1ll*x-y+mod)%mod;
}
}
if( type==1 ) return;
int inv = quick(limit,mod-2);
for(int i=0;i<limit;i++) a[i] = 1ll*a[i]*inv%mod;
}
void mul(int *a,int *b,int n,int m)
{
int limit = 1;
while( limit<=n+m ) limit<<=1;
for(int i=0;i<limit;i++) r[i] = ( r[i>>1]>>1 ) | ( (i&1)?limit>>1:0 );
for(int i=0;i<limit;i++)
{
if( i>=n ) a[i] = 0;
if( i>=m ) b[i] = 0;
}
NTT(a,limit,1); NTT(b,limit,1);
for(int i=0;i<limit;i++) a[i] = 1ll*a[i]*b[i]%mod;
NTT(a,limit,-1);
}
vector<int>vec;
signed main()
{
scanf("%d%d",&m,&n);
scanf("%s%s",t,s);
reverse(t,t+m );
int limit = 1;
while( limit<=n+m ) limit<<=1;
for(int i=0;i<n;i++) f[i] = s[i]=='*'?0:pow(s[i]-'0',3);
for(int i=0;i<m;i++) g[i] = t[i]=='*'?0:pow(t[i]-'0',1);
mul(f,g,n,m);
for(int i=0;i<limit;i++) ans[i] = ( 1ll*ans[i]+f[i+m-1] )%mod;
for(int i=0;i<n;i++) f[i] = s[i]=='*'?0:pow(s[i]-'0',1);
for(int i=0;i<m;i++) g[i] = t[i]=='*'?0:pow(t[i]-'0',3);
mul(f,g,n,m);
for(int i=0;i<limit;i++) ans[i] = ( 1ll*ans[i]+f[i+m-1] )%mod;
for(int i=0;i<n;i++) f[i] = s[i]=='*'?0:pow(s[i]-'0',2);
for(int i=0;i<m;i++) g[i] = t[i]=='*'?0:pow(t[i]-'0',2);
mul(f,g,n,m);
for(int i=0;i<limit;i++) ans[i] = ( 1ll*ans[i]-2*f[i+m-1] )%mod;
for(int i=0;i<=n-m;i++)
if( ans[i]==0 ) vec.push_back(i+1);
printf("%d\n",vec.size() );
for(int i=0;i<vec.size();i++)
printf("%d ",vec[i] );
}
但是 T T T了…
无奈,只能一直把正变换累加到 a n s ans ans去,然后一次性做掉逆变换, A C AC AC
#include <bits/stdc++.h>
using namespace std;
const int maxn = 6e6+10;
const int mod = 998244353,G=3,GI = 332748118;
int r[maxn],f[maxn],g[maxn],ans[maxn],n,m;
char s[maxn],t[maxn];
int quick(int x,int n)
{
int ans = 1;
for( ; n ; n>>=1,x=1ll*x*x%mod )
if( n&1 ) ans = 1ll*ans*x%mod;
return ans;
}
void NTT(int *a,int limit,int type)
{
for(int i=0;i<limit;i++) if( i<r[i] ) swap(a[i],a[r[i]]);
for(int mid = 1;mid<limit;mid<<=1)
{
int wn = quick( (type==1)?G:GI,(mod-1)/(mid<<1));
for(int R=mid<<1,i=0;i<limit;i+=R)
for(int k=0,w=1;k<mid;k++,w=1ll*w*wn%mod)
{
int x = a[i+k], y = 1ll*w*a[i+k+mid]%mod;
a[i+k] = (1ll*x+y)%mod, a[i+k+mid] = (1ll*x-y+mod)%mod;
}
}
if( type==1 ) return;
int inv = quick(limit,mod-2);
for(int i=0;i<limit;i++) a[i] = 1ll*a[i]*inv%mod;
}
void mul(int *a,int *b,int n,int m)
{
int limit = 1;
while( limit<=n+m ) limit<<=1;
for(int i=0;i<limit;i++) r[i] = ( r[i>>1]>>1 ) | ( (i&1)?limit>>1:0 );
for(int i=0;i<limit;i++)
{
if( i>=n ) a[i] = 0;
if( i>=m ) b[i] = 0;
}
NTT(a,limit,1); NTT(b,limit,1);
for(int i=0;i<limit;i++) a[i] = 1ll*a[i]*b[i]%mod;
}
vector<int>vec;
signed main()
{
scanf("%d%d",&m,&n);
scanf("%s%s",t,s);
reverse(t,t+m );
int limit = 1;
while( limit<=n+m ) limit<<=1;
for(int i=0;i<n;i++) f[i] = s[i]=='*'?0:pow(s[i]-'0',3);
for(int i=0;i<m;i++) g[i] = t[i]=='*'?0:pow(t[i]-'0',1);
mul(f,g,n,m);
for(int i=0;i<limit;i++) ans[i] = ( 1ll*ans[i]+f[i] )%mod;
for(int i=0;i<n;i++) f[i] = s[i]=='*'?0:pow(s[i]-'0',1);
for(int i=0;i<m;i++) g[i] = t[i]=='*'?0:pow(t[i]-'0',3);
mul(f,g,n,m);
for(int i=0;i<limit;i++) ans[i] = ( 1ll*ans[i]+f[i] )%mod;
for(int i=0;i<n;i++) f[i] = s[i]=='*'?0:pow(s[i]-'0',2);
for(int i=0;i<m;i++) g[i] = t[i]=='*'?0:pow(t[i]-'0',2);
mul(f,g,n,m);
for(int i=0;i<limit;i++) ans[i] = ( 1ll*ans[i]-2*f[i] )%mod;
NTT(ans,limit,-1);
for(int i=0;i<=n-m;i++)
if( ans[i+m-1]==0 ) vec.push_back(i+1);
printf("%d\n",vec.size() );
for(int i=0;i<vec.size();i++)
printf("%d ",vec[i] );
}