题意:
给你一个数组A,再给你一个数组B,我们可以任意将数组B整体增加或者减少值X(整数),我们可以进行修改值的操作无限次,每次我们要在数组A中找寻有几段和数组B完全匹配的子段。
思路:
可以发现由于可以将这个区间的数整体增加或减少一个数,因此该题匹配的重点不再是对于某个点的匹配,而是相邻点之间的差,因此我们需要维护一个差分数组。
让差分数组进行匹配即可。
总结:
差分作为一个比较常用的方法,主要适用于一些涉及相邻两点的差的一些题目。
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define rep(i,a,b) for(int i = a; i <= b; i++)
using namespace std;
const int N = 1e6+100;
int a[N],b[N],a1[N],b1[N];
int n,m;
int nxt[N];
void get(int* s)
{
memset(nxt,0,sizeof nxt);
int j = 0;
int l = m;
for(int i = 2;i <= l;i ++)
{
while(j && s[j+1] != s[i]) j = nxt[j];
if(s[j+1] == s[i]) j ++;
nxt[i] = j;
}
}
int find(int* s1,int* s2) //s2为子串
{
get(s2);
int j = 0;
int cnt = 0;
int l = m;
int ll = n;
int tmp = 0;
for(int i = 1;i <= ll;i ++)
{
while(j && s1[i] != s2[j+1]) j = nxt[j];
if(s1[i] == s2[j+1]) j ++;
if(j == l) cnt++,j = nxt[j];
}
return cnt;
}
int main()
{
scanf("%d%d",&n,&m);
rep(i,1,n)
scanf("%d",&a[i]);
rep(i,1,m)
scanf("%d",&b[i]);
if(m == 1) printf("%d\n",n);
else if(n < m) printf("0\n");
else{
rep(i,2,n) a1[i-1] = a[i]-a[i-1];
rep(i,2,m) b1[i-1] = b[i]-b[i-1];
n--,m--;
printf("%d\n",find(a1,b1));
}
return 0;
}
/*
字符串均从1开始编号
next[i] 表示 1~i 子串前后缀匹配的长度
循环节为 len-next[len]
*/
/*
11 4
3 4 5 6 7 8 9 10 11 12 13
2 3 4 5
*/