luogu P4173 残缺的字符串

题面传送门
没想到卷积还能做匹配。学到了学到了。
首先我们将\(A\)反序,这样我们就要\(A_{j}\)和\(B_{j-i}\)相同。
如果我们将两个这样的设一个权值,那么如果一个数全部加起来为\(0\),就是可以匹配的。
我们可以设为\((A_j-B_{i-j})^2\)
但是这里有通配符。
如果我们把权值改为\(A_jB_{i-j}(A_j-B_{i-j})^2\)就好了,然后将通配符设为\(0\)
然后这个就是\(7\)次\(NTT\)即可。
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 1100000
#define M 200000
#define mod 998244353
#define eps (1e-7)
#define U unsigned int
#define IT set<ques>::iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
using namespace std;
int n,m,k,A[N+5],B[N+5],tr[N+5],cnt;ll invn,C[N+5],A1[N+5],B1[N+5],A2[N+5],B2[N+5],A3[N+5],B3[N+5];char s1[N+5],s2[N+5];
I ll mpow(ll x,int y=mod-2){ll ans=1;while(y) (y&1)&&(ans=ans*x%mod),x=x*x%mod,y>>=1;return ans;}const ll G=3,invG=mpow(G);
I void swap(ll &x,ll &y){x^=y^=x^=y;}
I void NTT(ll *A,int n,int flag){
	int i,j,h;ll pus,now,key;for(i=0;i<n;i++) i<tr[i]&&(swap(A[i],A[tr[i]]),0);
	for(i=2;i<=n;i<<=1){
		for(key=mpow(flag?G:invG,(mod-1)/i),j=0;j<n;j+=i) {
			for(now=1,h=j;h<j+i/2;h++) pus=A[h+i/2]*now%mod,A[h+i/2]=(A[h]-pus+mod)%mod,A[h]=(A[h]+pus)%mod,now=now*key%mod; 
		}
	}
}
int main(){
	freopen("1.in","r",stdin);
	re int i;scanf("%d%d",&n,&m);scanf("%s%s",s1,s2);for(i=0;i<n;i++) A[n-i-1]=(s1[i]=='*'?0:s1[i]-'a'+1);
	for(i=0;i<m;i++)B[i]=(s2[i]=='*'?0:s2[i]-'a'+1);for(k=1;k<=n+m;k<<=1);for(i=0;i<k;i++) tr[i]=(tr[i>>1]>>1)|((i&1)?(k>>1):0);
	for(i=0;i<n;i++) A1[i]=A[i]*A[i]*A[i],A2[i]=A[i]*A[i],A3[i]=A[i];for(i=0;i<m;i++) B3[i]=B[i]*B[i]*B[i],B2[i]=B[i]*B[i],B1[i]=B[i];
	NTT(A1,k,1);NTT(A2,k,1);NTT(A3,k,1);NTT(B1,k,1);NTT(B2,k,1);NTT(B3,k,1);for(i=0;i<k;i++) C[i]=(A1[i]*B1[i]+A3[i]*B3[i]-2*A2[i]*B2[i])%mod+mod;
	NTT(C,k,0);invn=mpow(k);for(i=n-1;i<m;i++) C[i]=C[i]*invn%mod,cnt+=!C[i];printf("%d\n",cnt);for(i=n-1;i<m;i++) !C[i]&&(printf("%d ",i-n+2));
}
上一篇:做题记录 Luogu P2278


下一篇:【luogu CF1119F】【luogu P7600】Niyaz and Small Degrees / 封闭道路