题目描述
给定一个含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
思路:
这道题想到用 kmp,不过刚开始想的是,用两个数的差和前两个数的差相等(第一个数特殊考虑),不过这样想有问题而且麻烦。
同学告诉我,可以去求得这些数的差值:
样例可化为: 7 4
0 2 -3 0 2 -3
0 2 -3
这样就变成 纯正的 kmp 了。
#include <iostream> using namespace std; int n, m; // n 主串长度, m 模式串长度 const int N = 1000100; int nextt[N]; int x[N]; // 模式串 int y[N]; // 主串 // 对模式串进行处理 void kmp_pre() { int i, j; j = nextt[0] = -1; i = 0; while(i<m) { while(-1!=j && x[i]!=x[j]) j=nextt[j]; nextt[++i] = ++j; } } int kmp_count() { int i, j; int ans = 0; kmp_pre(); i = 0, j = 0; while(i < n) { while(-1!=j && y[i]!=x[j]) j=nextt[j]; i++; j++; if(j >= m) { ans ++; j = nextt[j]; } } return ans; } int main() { cin >> n >> m; for(int i=0; i<n; i++){ cin >> y[i]; } for(int i=0; i<m; i++) { cin >> x[i]; } n --, m --; for(int i=0; i<n; i++){ y[i] = y[i+1]-y[i]; } for(int i=0; i<m; i++){ x[i] = x[i+1]-x[i]; } // 输出 kmp 得到的数目 cout << kmp_count() << endl; return 0; }