1. 程式人生 > >HDU Problem - 5918 Sequence I

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;
}