1. 程式人生 > >【CodeForces - 471D 】【構造差分kmp】MUH and Cube Walls

【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
*/