解题思路:
其实一开始我只想到了暴力的方法,复杂度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;
}