牛客 栗酱的数列 (KMP)

牛客 栗酱的数列 (KMP)

传送门

题意:给a数组(n),b数组(m),模数k。问a有几个子串满足1<=i<=m,(a[i]+b[i])%k都相等。

题解:暴力匹配超时,这时候想到子串匹配算法KMP,但主要是有一个C=(a[i]+b[i]),要求一个串的值都等于C,而在一次匹配成功后,C可能会改变,故直接拿a数组建nex数组直接跳是错误的。

我们发现a[i]+b[i]a[i+1]+b[i+1]那么只要满足a[i]-a[i-1]b[i]-b[i-1]就行,上面与下面相等的模型,完全符合kmp板子。

#include<iostream>
#include<cstring>
using namespace std;
const int N=2e5+7;
int T,n,m,k,ans;
int a[N],b[N];
int s[N],t[N];
int nex[N];
void kmp(){
	int l=0,r=1;
	nex[l]=-1;
	while(r<m){
		if(l==-1||s[l]==s[r]){
			l++;
			r++;
			nex[r]=l;
		}
		else{
			l=nex[l];
		}
	}
}

void gao(){
	int p1=0;
	int p2=0;
	while(p2<n){
		if(p1==-1||(s[p1]+t[p2])%k==0){
			p1++;
			p2++;
			if(p1==m){
				ans++;
				p1=nex[p1];
			}
		}
		else{
			p1=nex[p1];
		}
	}
}
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d%d%d",&n,&m,&k);
		for(int i=0;i<n;i++){
			scanf("%d",&a[i]);
			a[i]%=k;
		}
		for(int i=0;i<m;i++){
			scanf("%d",&b[i]);
			b[i]%=k;
		}
		n--;
		m--;
		ans=0;
		for(int i=0;i<n;i++){
			t[i]=(a[i+1]-a[i]+k)%k;
		}
		for(int i=0;i<m;i++){
			s[i]=(b[i+1]-b[i]+k)%k;
		}
		kmp();
		gao();
		printf("%d\n",ans);
	}
}
posted @ 2021-03-27 00:26  ccsu_madoka  阅读(76)  评论(0编辑  收藏  举报