HDU Problem - 5918 Sequence I

题目链接

Problem Description

Mr. Frog has two sequences a 1 , a 2 , , a n and b 1 , b 2 , , b m and a number p. He wants to know the number of positions q such that sequence b 1 , b 2 , , b m is exactly the sequence a q , a q + p , a q + 2 p , , a q + ( m 1 ) p where q + ( m 1 ) p n and q 1 .

Input

The first line contains only one integer T 100 , which indicates the number of test cases.Each test case contains three lines.The first line contains three space-separated integers 1 n 10 6 , 1 m 10 6 and 1 p 10 6 .The second line contains n integers a 1 , a 2 , , a n ( 1 a i 10 9 ) .the third line contains m integers b 1 , b 2 , , b m ( 1 b i 10 9 ) .

Output

For each test case, output one line “Case #x: y”, where x is the case number (starting from 1) and y is the number of valid q’s.

Sample Input

2

6 3 1

1 2 3 1 2 3

1 2 3

6 3 2

1 3 2 2 3 1

1 2 3

Sample Output

Case #1: 2

Case #2: 1

AC

  • 在a数组中匹配b,每次间隔p,如果每次间隔1的话,直接一个kmp就可以,但是间隔2以上就要枚举所有的区间进行kmp,要不然会漏掉
  • 例如a数组:1,1,2,2,3,3,b数组:1, 2, 3 p = 2,如果只是从0开始跑kmp,只会得到1对应a数组中下标为(0,2,4),但是(1,3,5)就漏掉了
  • 所以在满足可以构成M个数的前提下,保证所有的区间恰好都覆盖
#include <iostream>
#include <stdio.h>
#include <map>
#include <vector>
#include <set>
#include <cstring>
#include <cmath>
#include <algorithm>
#define N 1000005
#define ll  long long
using namespace std;
int a[N], b[N], pre[N];
void get_next(int m) {
    int i = 0, j = -1;
    pre[0] = -1;
    while (i < m) {
        if (b[i] == b[j] || j == -1)
            pre[++i] = ++j;
        else
            j = pre[j];
    }
}

int kmp(int start, int n, int m, int p) {
    int ans = 0;
    get_next(m);
    int i = start, j = 0;
    while (i < n) {
        if (j == -1 || a[i] == b[j])
            j++, i += p;
        else
            j = pre[j];
        if (j == m)
            ans++, j = pre[j];  
    }
    return ans;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif
    int t;
    scanf("%d", &t);
    int Case = 1;
    while (t--) {
        int n, m, p;
        scanf("%d%d%d", &n, &m, &p);
        for (int i = 0; i < n; ++i) {
            scanf("%d", &a[i]);
        }
        for (int i = 0; i < m; ++i) {
            scanf("%d", &b[i]);
        }
        int ans = 0;
        // 枚举所有区间 
        for (int i = 0; i < p; ++i) {
            // 保证构成M个数 
            if (i + m * p - p <= n - 1)
                ans += kmp(i, n, m, p);
            else
                break;
        }
        printf("Case #%d: %d\n", Case++, ans);
    } 
    return 0;
}

猜你喜欢

转载自blog.csdn.net/henuyh/article/details/82181099
今日推荐