首页 > 其他分享 >Prefix Function Queries

Prefix Function Queries

时间:2022-10-21 22:35:10浏览次数:81  
标签:Function return int kmp Prefix nex Queries typ mod

传送门

感觉字符串只会 hash 了。

这里提几点易错点:

① 字符串能不用 string 就不用。 反正这道题因为 string 的 size (不能正常清空)和读入 Wa 飞了

② hash 都写双模数。单模数太容易被卡。

#include<bits/stdc++.h>
using namespace std;
const int mod[2]={998244353,1000000007},Len=1000007,P[2]={131,127};
int head[Len],nex[10000001],ans[10000001],st[10000001],ed[10000001],tot;
int h[2][1000005],p[2][1000005],hh[2][12];
char ss[1000007],s[12];
inline int get(int typ,int l,int r){
	if(l>r)return 0;
	return ((h[typ][r]-1ll*h[typ][l-1]*p[typ][r-l+1]%mod[typ])%mod[typ]+mod[typ])%mod[typ];
}
inline int gethh(int typ,int l,int r){
	if(l>r)return 0;
	return ((hh[typ][r]-1ll*hh[typ][l-1]*p[typ][r-l+1]%mod[typ])%mod[typ]+mod[typ])%mod[typ];
}
inline bool pd(int l1,int r1,int l2,int r2){
	if(r1-l1!=r2-l2)return 0;
	for(int i=0;i<=r1-l1;++i){
		if(ss[l1+i]!=ss[l2+i])return 0;
	}
	return 1;
}
inline bool pd2(int l1,int r1,int l2,int r2){
	if(r1-l1!=r2-l2)return 0;
	for(int i=0;i<=r1-l1;++i){
		if(ss[l1+i]!=s[l2+i])return 0;
	}
	return 1;
}
int main(){
//	cout<<(sizeof(ss)>>20)<<endl;
	//std::ios::sync_with_stdio(false);
	scanf("%s",1+ss);
	int n=strlen(1+ss);
//	cout<<n<<endl;
//	ss='0'+ss;
	for(int t=0;t<2;++t){
		p[t][0]=1;
		for(int i=1;i<=n;++i)h[t][i]=(1ll*h[t][i-1]*P[t]%mod[t]+ss[i]-'a'+1)%mod[t],p[t][i]=1ll*p[t][i-1]*P[t]%mod[t];
		for(int i=1;i<=10;++i)p[t][i]=1ll*p[t][i-1]*P[t]%mod[t];
	}
	for(int len=0;len<n;++len){
		if(get(0,1,len)==get(0,n-len+1,n)&&get(1,1,len)==get(1,n-len+1,n)){
			for(int i=1;i<=min(n-len,10);++i){
				int sum=get(0,len+1,len+i)%Len,j=head[sum];
				while(j){
					if(pd(st[j],ed[j],len+1,len+i)){
						ans[j]=len;
						break;
					}
				}
				if(!j){
					nex[++tot]=head[sum],head[sum]=tot;ans[tot]=len;st[tot]=len+1,ed[tot]=len+i;
				}
			}
		}
	}
//	cout<<get(1,1)<<" "<<get(n,n)<<endl;
//	for(int i=1;i<=tot;++i)cout<<ss[i]<<endl;
	int q;scanf("%d",&q);
	while(q--){
		scanf("%s",1+s);
		int t=strlen(1+s);
	//	cout<<t<<endl;
		for(int i=1;i<=t;++i){
			for(int T=0;T<2;++T)hh[T][i]=(1ll*hh[T][i-1]*P[T]+s[i]-'a'+1)%mod[T];
			int Ans=0;
			int j=head[hh[0][i]%Len];
			while(j){
				if(pd2(st[j],ed[j],1,i)){
					Ans=max(Ans,ans[j]+i);
					break;
				}
				j=nex[j];
			}
			for(int len=max(1,n-i+1);len<n;++len){
				if((1ll*get(0,n-len+1,n)*p[0][i]+hh[0][i])%mod[0]==(1ll*get(0,1,n)*p[0][i-n+len]%mod[0]+hh[0][i-n+len])%mod[0]&&
				(1ll*get(1,n-len+1,n)*p[1][i]+hh[1][i])%mod[1]==(1ll*get(1,1,n)*p[1][i-n+len]%mod[1]+hh[1][i-n+len])%mod[1])Ans=max(Ans,len+i);
			}
			for(int len=1;len<=min(i,n);++len){
				if(gethh(0,i-len+1,i)==get(0,1,len)&&gethh(1,i-len+1,i)==get(1,1,len))Ans=max(Ans,len);
			}
			if(i>n){
				for(int len=n+1;len<=i;++len){
					if(gethh(0,i-len+1,i)==(1ll*get(0,1,n)*p[0][len-n]%mod[0]+gethh(0,1,len-n))%mod[0]&&
					gethh(1,i-len+1,i)==(1ll*get(1,1,n)*p[1][len-n]%mod[1]+gethh(1,1,len-n))%mod[1])Ans=max(Ans,len);
				}
			}
			printf("%d ",Ans);
		}
		puts("");
	}
	return 0;
}
/*
string size cin
hash

detail
*/

下面给出字符串做法。

其实看到 prefix function 就应该想到 kmp 的了。

最自然朴素的做法就是预处理 \(s\) 的 \(nex\) 数组,然后每次从 \(|s|+1\) 开始跑 \(s+t\)。

虽然单纯的 kmp 时间复杂度是 \(O(N)\),但若是 \(s=aaa...aaa,t=b\) 那每次都得跑 \(O(N)\),这样肯定会 TLE。

注意到复杂度瓶颈在于 \(nex\) 的跳动。那么我们设 \(kmp[i][k]\) 表示 \(i\) 所对应的 \(j,nex[j],nex[nex[j]]...\) 中,下一位为 \('a'+k\) 的最右位置,每次直接跳到对应位置。

这样总复杂度就稳定在 \(O(N\times |C|)\)

#include<bits/stdc++.h>
using namespace std;
#define N 1000015
int kmp[N][26];
char s[N],t[12];
inline int init(int n){
	for(int i=1,j=0;i<=n;++i){
		if(i!=1){
			if(!(j+1!=i&&s[j+1]==s[i]))j=kmp[j][s[i]-'a'];
			if(s[j+1]==s[i])++j;
		}
		for(int k=0;k<26;++k)kmp[i][k]=kmp[j][k];
		kmp[i][s[j+1]-'a']=j;
		if(i==n)return j;
	}
}

int main(){
	scanf("%s",1+s);
	int q,n,m;cin>>q;
	n=strlen(1+s);
	int las=init(n);
	while(q--){
		scanf("%s",1+t);
		m=strlen(1+t);
		for(int i=n+1,j=las;i<=m+n;++i){
			s[i]=t[i-n];
			if(!(j+1!=i&&s[j+1]==s[i]))j=kmp[j][s[i]-'a'];
			if(s[j+1]==s[i])++j;
			printf("%d ",j);
			for(int k=0;k<26;++k)kmp[i][k]=kmp[j][k];
			kmp[i][s[j+1]-'a']=j;
		}
		puts("");
	}
	return 0;
}

标签:Function,return,int,kmp,Prefix,nex,Queries,typ,mod
From: https://www.cnblogs.com/Huster-ZHY/p/16814979.html

相关文章