牛客网-栗酱的数列(kmp)

解题思路:

其实一开始我只想到了暴力的方法,复杂度mn.后来网上找了题解https://blog.csdn.net/m0_37134257/article/details/78884367

发现竟然还可以用kmp做,因为题目要求(a'1+b1)%k = (a'2+b2)%k = …… = (a'm + bm)%k。那么可以改造一下,变成

((a2-a1)+(b2-b1))%k==0,这样就有可比性了。分成(a2-a1)项和(b2-b1)项,这种形式之和自己数组内的数有关,可以建立next数组。

#include<cstdio>
#include<cstring>
using namespace std;
long long s1[200009],s2[200009],d1[200009],d2[200009],next[200009];
int n,m;
void build_next(long long d[])
{
	int l=m;
	memset(next,-1,sizeof(next));
	int j=-1;
	for(int i=1;i<l;i++)
	{
		while(j>-1&&d[j+1]!=d[i])
		j=next[j];
		if(d[j+1]==d[i]) j++;
		next[i]=j;
	}
}
int main()
{
	int T,k;
	//freopen("t.txt","r",stdin);
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d%d",&n,&m,&k);
		for(int i=0;i<n;i++) 
		{
			scanf("%d",&s1[i]);
			s1[i]%=k;
		}
		for(int i=0;i<m;i++) 
		{
			scanf("%d",&s2[i]);
			s2[i]%=k;
		}
		for(int i=1;i<n;i++) d1[i-1]=(s1[i]-s1[i-1]+k)%k;
		for(int i=1;i<m;i++) d2[i-1]=(s2[i]-s2[i-1]+k)%k;
		n--;m--;
		build_next(d2);
		int j=-1,i=0;
		long long ans=0;
		while(i<n)
		{
			while(j>-1&&(d2[j+1]+d1[i])%k!=0)
			j=next[j];
			if((d2[j+1]+d1[i])%k==0) j++;
			i++;
			if(j>=m-1)
			{
				ans++;
				j=next[j];
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39861441/article/details/88542513