Sequence I
Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1105 Accepted Submission(s): 423
Problem Description
Mr. Frog has two sequences a1,a2,⋯,an and b1,b2,⋯,bm and a number p. He wants to know the number of positions q such that sequence b1,b2,⋯,bm is exactly the sequence aq,aq+p,aq+2p,⋯,aq+(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≤106,1≤m≤106 and 1≤p≤106.
The second line contains n integers a1,a2,⋯,an(1≤ai≤109).
the third line contains m integers b1,b2,⋯,bm(1≤bi≤109).
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
题意:给定三个数字n, m, p和两个序列a, b,n, m, p分别表示a,b序列的长度,和不去a匹配的时候在a中匹配时每次向后匹配的下表示+p不是+1;求出在a中一共有几个匹配串
分析:只是一道典型的kmp问题(这里就不讲kmp模版了,不会的请移步kmp),只是在匹配串中匹配时下标移动的速度变成了每次移动p位,但如果只是单纯的改变kmp模版里的循环每次移动的位置那时错的,因为这样活漏掉一些点,所以对于匹配串中的每个i都必须匹配过一次(不是每给数作为开头匹配一次,而是匹配过一次),那么只要循环for(int s = 0 ; s < p; s++)这些串作为开头就可以了。
简单的说就是把序列a[]分成p个串,每个串的开头是s那么当前这条串就是for(int i = s; i < n; i += p)
代码:
//
// main.cpp
// HDU-Fighting
//
// Created by sun000 on ...
// Copyright © 2016年 sun000. All rights reserved.
//
#include <cstdio>
#include <cstring>
const int MAXN = 1e6 + 10;
int a[MAXN], b[MAXN], f[MAXN], n, m, p, ans;
void getFail()
{
f[0] = 0;
f[1] = 0;
for(int i = 1; i < m; i++)
{
int j = f[i];
while(j && b[i] != b[j])
j = f[j];
if(b[i] == b[j])
f[i + 1] = j + 1;
else
f[i + 1] = 0;
}
}
void find()
{
getFail();
for(int s = 0; s < p; s++)
{
for(int i = s, j = 0; i < n; i += p)//每次i下后跳p个位子
{
while(j && a[i] != b[j])
j = f[j];
if(a[i] == b[j])
j++;
if(j == m)
{
j = 0;//j重新回到第一个数字开始匹配
i = i - (m - 1) * p;//i指向当前数字的"下一个"数字(实际上这里回到了开头,因为待会会+=p)
ans++;
// return i - m + 1;
}
}
}
}
int main(void)
{
int t;
scanf("%d", &t);
for(int cas = 1; cas <= t; cas++)
{
ans = 0;
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]);
find();
printf("Case #%d: %d\n", cas, ans);
}
return 0;
}