【CodeForces - 471D 】【构造差分kmp】MUH and Cube Walls

题意:

      给你一个数组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
*/

猜你喜欢

转载自blog.csdn.net/qq_41552508/article/details/83792210