CF1334G Substring Search

题目传送门

分析:
我们先看看如果不需要置换,我们如何将\(S\)匹配进\(T\)
(废话当然是kmp或者hash了
能否用函数求解呢?
两个字符\(S_i,T_j\)相同,当且仅当\((S_i-T_j)^2=0\)
于是对于串\(T\),以结束位置为自变量做一个函数\(P(x)\),把\(S\)串反转

\(P(x)=\sum_{i=1}^{m}(S_i-T_{x+i-m})^2\)

\(P(x)=0\)时,说明这个位置结束的串可以匹配
式子展开,中间的\(S_{i}T_{j}\)用NTT求一下就好了

接下来考虑置换,同理
两个字符\(S_i,T_j\)相同,当且仅当\((S_i-T_j)^2(P_{S_i}-T_j)^2=0\)
同样适用NTT求解(但是要做7次)
我反正没卡过时限,考虑奇奇怪怪的技巧
我们尝试把平方抹去,\(P(x)\)变成

\(P(x)=\sum_{i=1}^{m}(S_i-T_{x+i-m})(P_{S_i}-T_{x+i-m})\)

这个明显是错误的,在\(S\)\(T\)值域只有\([1,26]\)时随随便便就挂了
那就把值域变一下,把每个字符的值在NTT模数取模下随机
这样正确率就很高了
(还可能被卡?换个NTT模数,998244353众人皆知,1004535809就很棒
我用的998244353,到时候视情况而定吧(也可以随机两次或者三次来做
反正就是乱搞(

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<queue>
#include<algorithm>

#define maxn 800005
#define INF 0x3f3f3f3f
#define MOD 998244353

using namespace std;

inline long long getint()
{
	long long num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

int n,m;
int A[maxn],B[maxn],F[maxn],G[maxn],H[maxn],p[maxn],P[maxn];
int pre[maxn],rev[maxn],w[maxn];
char S[maxn],T[maxn];
int ans,sum;

inline int upd(int x){return x<MOD?x:x-MOD;}
inline int ksm(int num,int k)
{
	int ret=1;
	for(;k;k>>=1,num=1ll*num*num%MOD)if(k&1)ret=1ll*ret*num%MOD;
	return ret;
}

inline void NTT(int *a,int len,int op)
{
	for(int i=0;i<len;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
	for(int i=1;i<len;i<<=1)for(int j=0,wn=ksm(op==1?3:332748118,(MOD-1)/(i<<1));j<len;j+=(i<<1))
		for(int k=0,w=1;k<i;k++,w=1ll*w*wn%MOD)
		{
			int x=a[j+k],y=1ll*a[i+j+k]*w%MOD;
			a[j+k]=upd(x+y),a[i+j+k]=upd(x-y+MOD);
		}
	if(!~op)for(int i=0,Inv=ksm(len,MOD-2);i<len;i++)a[i]=1ll*a[i]*Inv%MOD;
}

inline void mul(int *a,int *b)
{
	int len=1;
	while(len<(n+m))len<<=1;
	for(int i=0;i<len;i++)rev[i]=(rev[i>>1]>>1)|(i&1?len>>1:0);
	NTT(a,len,1),NTT(b,len,1);
	for(int i=0;i<len;i++)a[i]=1ll*a[i]*b[i]%MOD;
	NTT(a,len,-1);
}

int main()
{
	for(int i=1;i<=26;i++)p[i]=getint();
	scanf("%s%s",S,T);
	n=strlen(T),m=strlen(S);
	for(int i=0;i<m-i-1;i++)swap(S[i],S[m-i-1]);
	for(int i=1;i<=26;i++)w[i]=ksm(p[i],INF);
	for(int i=0;i<n;i++)
	{
		F[i]=w[T[i]-96];
		pre[i]=upd((i?pre[i-1]:0)+1ll*F[i]*F[i]%MOD);
	}
	for(int i=0;i<m;i++)
	{
		G[i]=w[S[i]-96];
		H[i]=w[p[S[i]-96]];
		sum=upd(sum+1ll*G[i]*H[i]%MOD);
	}
	for(int i=0;i<n;i++)A[i]=F[i];
	for(int i=0;i<m;i++)B[i]=upd(G[i]+H[i]);
	mul(A,B);
	for(int i=0;i<n+m;i++)P[i]=upd(MOD-A[i]);
	for(int i=m-1;i<n;i++)
	{
		P[i]=upd(P[i]+upd(pre[i]-(i>=m?pre[i-m]:0)+MOD));
		P[i]=upd(P[i]+sum);
		printf("%d",!P[i]);
	}
	printf("\n");
}

posted @ 2020-05-27 19:07  Izayoi_Doyo  阅读(293)  评论(0编辑  收藏  举报