2018牛客网暑假ACM多校训练赛(第三场)D Encrypted String Matching 多项式 FFT

原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round3-D.html

题目传送门 - 2018牛客多校赛第三场 D

题意

  给定两个字符串,在根据给定的字符表转成相应的字符之后,问前一个串在后面一个串中匹配了多少次。

  一个串在另一个串的某一个位置匹配,当且仅当从该位置起截取长度与那个串相同的一个子串,这个子串与那个串等价。

  定义两个串等价,当且仅当这两个串的对应位置的 Ascll 码值相差不大于 1 。

  任意一个串的长度 $leq 250000$。

题解

  FFT 基础套路题。

  为了偷懒,我们写 11 次 DFT 。

  但是这样做 double 精度不大行,long double 要超时。

  所以我们用 NTT 来搞定。

  注意别爆 long long 。

  关于 FFT 和套路介绍,下面这个链接所指向的博文有详细介绍。

  https://www.cnblogs.com/zhouzhendong/p/Fast-Fourier-Transform.html

  

  套路:

  首先将第一个串翻转一下。

  然后构造式子:

  $f_i=sum_{j=0}^{i} (S_i-T_j)^2((S_i-T_j)^2-1)$

  展开之后 NTT 算出来就可以了。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1<<22,mod=998244353;
int a,b,n,d;
int S[N],T[N],R[N];
char S1[N],T1[N];
char s[27];
int Pow(int x,int y){
	int ans=1;
	for (;y;y>>=1,x=1LL*x*x%mod)
		if (y&1)
			ans=1LL*ans*x%mod;
	return ans;
}
int w[N],A[N];
int A4[N],A3[N],A2[N],A1[N],A0[N];
int B4[N],B3[N],B2[N],B1[N],B0[N];
void FFT(int a[],int n){
	for (int i=0;i<n;i++)
		if (i<R[i])
			swap(a[i],a[R[i]]);
	for (int t=n>>1,d=1;d<n;d<<=1,t>>=1)
		for (int i=0;i<n;i+=(d<<1))
			for (int j=0;j<d;j++){
				int tmp=1LL*w[t*j]*a[i+j+d]%mod;
				a[i+j+d]=(a[i+j]-tmp)%mod;
				a[i+j]=(a[i+j]+tmp)%mod;
			}
}
vector <int> vec;
int main(){
	scanf("%s%s%s",S1,T1,s);
	a=strlen(S1),b=strlen(T1);
	for (int i=0;i<a;i++)
		S1[i]=s[S1[i]-'a'];
	for (int i=0;i<b;i++)
		T1[i]=s[T1[i]-'a'];
	for (int i=0;i<a;i++)
		S[a-i-1]=S1[i]-'a'+1;
	for (int i=0;i<b;i++)
		T[i]=T1[i]-'a'+1;
	for (n=1,d=0;n<a+b;n<<=1,d++);
	for (int i=0;i<n;i++)
		R[i]=(R[i>>1]>>1)|((i&1)<<(d-1));
	w[0]=1,w[1]=Pow(3,(mod-1)/n);
	for (int i=2;i<n;i++)
		w[i]=1LL*w[i-1]*w[1]%mod;
	for (int i=0;i<n;i++){
		A0[i]=i<a?1:0;
		A1[i]=S[i];
		A2[i]=S[i]*S[i];
		A3[i]=S[i]*S[i]*S[i];
		A4[i]=S[i]*S[i]*S[i]*S[i];
		B0[i]=i<b?1:0;
		B1[i]=T[i];
		B2[i]=T[i]*T[i];
		B3[i]=T[i]*T[i]*T[i];
		B4[i]=T[i]*T[i]*T[i]*T[i];
	}
	FFT(A0,n),FFT(A1,n),FFT(A2,n),FFT(A3,n),FFT(A4,n);
	FFT(B0,n),FFT(B1,n),FFT(B2,n),FFT(B3,n),FFT(B4,n);
	for (int i=0;i<n;i++)
		A[i]=(1LL*A4[i]*B0[i]%mod
			 -4LL*A3[i]*B1[i]%mod
			 +6LL*A2[i]*B2[i]%mod
			 -4LL*A1[i]*B3[i]%mod
			 +1LL*B4[i]*A0[i]%mod
			 -1LL*A2[i]*B0[i]%mod
			 +2LL*A1[i]*B1[i]%mod
			 -1LL*B2[i]*A0[i]%mod)%mod;
	w[1]=Pow(w[1],mod-2);
	for (int i=2;i<n;i++)
		w[i]=1LL*w[i-1]*w[1]%mod;
	FFT(A,n);
	for (int i=0,inv=Pow(n,mod-2);i<n;i++)
		A[i]=1LL*A[i]*inv%mod;
	vec.clear();
	for (int i=0;i<b-a+1;i++)
		if (A[i+a-1]==0)
			vec.push_back(i+1);
	printf("%d
",(int)(vec.size()));
	for (int i=0;i<vec.size();i++)
		printf("%d ",vec[i]);
	return 0;
}

  

原文地址:https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round3-D.html