sequence

题目描述

给定一个含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;
}


猜你喜欢

转载自blog.csdn.net/qq_38737992/article/details/80056528