题目描述
给定一个含n个数的序列A和一个含m (m<=n) 个数的序列B。
询问在A中有多少段连续的长为m的子序列Ak,Ak+1,…,Ak+m-1使得对于任意1<=i, j<=m满足Ak+i-1-Bi=Ak+j-1-Bj
输入
第一行两个整数n,m (1 <= m <= n <= 106)
接下来一行n个整数,描述序列A (Ai <= 109)
接下来一行m个整数,描述序列B (Bi <= 109)
输出
输出一个数表示答案
样例输入
7 4
6 6 8 5 5 7 4
7 7 9 6
样例输出
2
思路
AC
#include<iostream>
#include<bits/stdc++.h>
#define N 1000006
using namespace std;
int a[N], b[N], Next[N];
void get_next(int m) { //求Next数组
Next[0] = -1;
int i = 0, j = -1;
while (i < m) {
if(j == -1 || b[i] == b[j]) {
Next[++i] = ++j; //赋值
}else {
j = Next[j]; //回溯
}
}
}
int kmp(int n, int m) {
get_next(m); //求Next数组
int i = 0, j = 0;
int ans = 0;
while (i < n) {
if (j == -1 || a[i] == b[j]) { //当前匹配成功进行下一个匹配
i++;
j++;
}else {
j = Next[j];
}
if (j == m) { //匹配成功
ans++;
j = Next[j]; //进行下一次匹配
}
}
return ans;
}
int main() {
// freopen("in.txt", "r", stdin);
int n, m;
while (scanf("%d%d", &n, &m) != EOF) {
for (int i = 0; i < n; i++) {
scanf("%d",&a[i]);
}
for (int i = 0; i < m; i++) {
scanf("%d", &b[i]);
}
if (m == 1) { //m = 1 特判
printf("%d\n", n);
continue;
}
for (int i = 1; i < n; i++) {
a[i - 1] = a[i] - a[i - 1];
}
for (int i = 1; i < m; i++) {
b[i - 1] = b[i] - b[i - 1];
}
printf("%d\n", kmp(n - 1, m - 1));
}
return 0;
}