A - Number Sequence

Given two sequences of numbers : a[1], a[2], …… , a[N], and b[1], b[2], …… , b[M] (1 <= M <= 10000, 1 <= N <= 1000000). Your task is to find a number K which make a[K] = b[1], a[K + 1] = b[2], …… , a[K + M - 1] = b[M]. If there are more than one K exist, output the smallest one.

Input

The first line of input is a number T which indicate the number of cases. Each case contains three lines. The first line is two numbers N and M (1 <= M <= 10000, 1 <= N <= 1000000). The second line contains N integers which indicate a[1], a[2], …… , a[N]. The third line contains M integers which indicate b[1], b[2], …… , b[M]. All integers are in the range of [-1000000, 1000000].

Output

For each test case, you should output one line which only contain K described above. If no such K exists, output -1 instead.

Sample Input

1
2
3
4
5
6
7
2
13 5
1 2 1 2 3 1 2 3 1 3 2 1 2
1 2 3 1 3
13 5
1 2 1 2 3 1 2 3 1 3 2 1 2
1 2 3 2 1

Sample Output

1
2
6
-1

题目大意:找到子串的位置,返回第一个下标,否则返回-1

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stdio.h>
#include <string>
#include <cstring>
using namespace std;
int ne[10005];
int t[10005];
int s[1000005];
int lens,lent;
void getne()
{
int i,j;
j=-1,i=0;
ne[0]=-1;
//int len=strlen(t);
while(i<lent)
{
if(j==-1||t[i]==t[j])
{
j++;
i++;
ne[i]=j;
}
else
{
j=ne[j];
}
}
}
int KMP()
{
int i,j;
j=0,i=0;

while(i<lens&&j<lent)
{
if(j==-1||s[i]==t[j])
{
i++;
j++;
}
else
{
j=ne[j];
}
}
if(j==lent)
{
return i-j+1;
}
else
return -1;
}

int main()
{
int n;
int m,x;

cin>>n;
while(n--)
{

cin>>m>>x;
for(int i=0;i<m;i++)
{
scanf("%d",&s[i]);

}
for(int i=0;i<x;i++)
{
scanf("%d",&t[i]);
}
memset(ne,0,sizeof(ne));
lent=x;
lens=m;
getne();
cout<<KMP()<<endl;
}
return 0;

}

B-Oulipo

The French author Georges Perec (1936–1982) once wrote a book, La disparition, without the letter ‘e’. He was a member of the Oulipo group. A quote from the book:

Tout avait Pair normal, mais tout s’affirmait faux. Tout avait Fair normal, d’abord, puis surgissait l’inhumain, l’affolant. Il aurait voulu savoir où s’articulait l’association qui l’unissait au roman : stir son tapis, assaillant à tout instant son imagination, l’intuition d’un tabou, la vision d’un mal obscur, d’un quoi vacant, d’un non-dit : la vision, l’avision d’un oubli commandant tout, où s’abolissait la raison : tout avait l’air normal mais…

Perec would probably have scored high (or rather, low) in the following contest. People are asked to write a perhaps even meaningful text on some subject with as few occurrences of a given “word” as possible. Our task is to provide the jury with a program that counts these occurrences, in order to obtain a ranking of the competitors. These competitors often write very long texts with nonsense meaning; a sequence of 500,000 consecutive ‘T’s is not unusual. And they never use spaces.

So we want to quickly find out how often a word, i.e., a given string, occurs in a text. More formally: given the alphabet {‘A’, ‘B’, ‘C’, …, ‘Z’} and two finite strings over that alphabet, a word W and a text T, count the number of occurrences of W in T. All the consecutive characters of W must exactly match consecutive characters of T. Occurrences may overlap.

Input

The first line of the input file contains a single number: the number of test cases to follow. Each test case has the following format:

One line with the word W, a string over {‘A’, ‘B’, ‘C’, …, ‘Z’}, with 1 ≤ |W| ≤ 10,000 (here |W| denotes the length of the string W).
One line with the text T, a string over {‘A’, ‘B’, ‘C’, …, ‘Z’}, with |W| ≤ |T| ≤ 1,000,000.

Output

For every test case in the input file, the output should contain a single number, on a single line: the number of occurrences of the word W in the text T.

Sample Input

1
2
3
4
5
6
7
3
BAPC
BAPC
AZA
AZAZAZA
VERDI
AVERDXIVYERDIAN

Sample Output

1
2
3
1
3
0

题目大意:求子串在母串中出现的次数

和上一题差不多,只需要统计即可

参考代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stdio.h>
#include <string>
#include <cstring>
using namespace std;
int ne[10005];
string s,t;
int lens,lent;
void getne()
{
int i,j;
j=-1,i=0;
ne[0]=-1;
while(i<lent)
{
if(j==-1||t[i]==t[j])
{
j++;
i++;
ne[i]=j;
}
else
{
j=ne[j];
}
}
}
int KMPCOUNT()
{
int i,j;
j=0,i=0;
int count=0;
if(lent==1&&lens==1)
{
if(s[0]==t[0])
return 1;
else
return 0;
}
while(i<lens&&j<lent)
{
if(j==-1||s[i]==t[j])
{
i++;
j++;
}
else
{
j=ne[j];
}
if(j==lent)
{
j=ne[j];
count++;
}
}

return count;
}

int main()
{
int n;
cin>>n;
while(n--)
{
cin>>t;
cin>>s;
lent=t.size();
lens=s.size();
getne();
cout<<KMPCOUNT()<<endl;
}

}

C - 剪花布条

一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案。对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢?

Input

输入中含有一些数据,分别是成对出现的花布条和小饰条,其布条都是用可见ASCII字符表示的,可见的ASCII字符有多少个,布条的花纹也有多少种花样。花纹条和小饰条不会超过1000个字符长。如果遇见#字符,则不再进行工作。

Output

输出能从花纹布中剪出的最多小饰条个数,如果一块都没有,那就老老实实输出0,每个结果之间应换行。

Sample Input

1
2
3
abcde a3
aaaaaa aa
#

Sample Output

1
2
0
3

这题和上一题略有不同,因为是减花布条,母串剪完就没有了,所以如果剪出一个布条以后,j要回溯到-1位置。

参考代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stdio.h>
#include <string>
#include <cstring>
using namespace std;
int ne[10005];
string s,t;
int lens,lent;
void getne()
{
int i,j;
j=-1,i=0;
ne[0]=-1;
while(i<lent)
{
if(j==-1||t[i]==t[j])
{
j++;
i++;
ne[i]=j;
}
else
{
j=ne[j];
}
}
}
int KMPCOUNT()
{
int i,j;
j=0,i=0;
int count=0;
if(lent==1&&lens==1)
{
if(s[0]==t[0])
return 1;
else
return 0;
}
while(i<lens&&j<lent)
{
if(j==-1||s[i]==t[j])
{
i++;
j++;
}
else
{
j=ne[j];
}
if(j==lent)
{
j=-1;
i--;//i在++以后已经不匹配了,要减1,回溯到上一步
count++;
}
}

return count;
}

int main()
{
while(cin>>s>>t&&s[0]!='#')
{
lent=t.size();
lens=s.size();
getne();
cout<<KMPCOUNT()<<endl;

}

}

exkmp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include<string>
#include <iostream>

using namespace std;
string s,x;
int lenx,lens;
int ne[1005];
int ex[1005];
void getne (){
ne[0] = lenx;
int a = 0 , p = 0;
for (int i=1;i<lenx ; i++){
if(i>=p || i+ne [i-a] >=p) {
p= max(p,i);
while(p<lenx && x[p]==x[p-i]) p++;
ne[i] = p-i;
a = i;
}
else ne [i] = ne[i-a];
}
}
void getex() {// s的每个后缀与x匹配前缀

getne () ;
int a = 0 , p = 0;
for (int i=0;i<lens; i++){
if(i>=p || i+ne [i-a] >=p) {
p = max(p,i);
while (p<lens &&p-i<lenx && s[p]==x[p-i]) p++;
ex[i]= p-i;
a = i;
}
else ex[i]= ne [i-a] ;
}
}
int main()
{
cin>>x>>s;
lenx=x.size();
lens=x.size();
getne();
getex();
for(int i=0;i<8;i++)
{
cout<<ne[i]<<" ";
}
cout<<endl;
for(int i=0;i<6;i++)
cout<<ex[i]<<" ";
cout<<endl;

}
//x:aaaaac
//S:aaaaabbb

D-Power Strings

Given two strings a and b we define ab to be their concatenation. For example, if a = “abc” and b = “def” then ab = “abcdef”. If we think of concatenation as multiplication, exponentiation by a non-negative integer is defined in the normal way: a^0 = “” (the empty string) and a^(n+1) = a*(a^n).

Input

Each test case is a line of input representing s, a string of printable characters. The length of s will be at least 1 and will not exceed 1 million characters. A line containing a period follows the last test case.

Output

For each s you should print the largest n such that s = a^n for some string a.

Sample Input

1
2
3
4
abcd
aaaa
ababab
.

Sample Output

1
2
3
1
4
3

Hint

This problem has huge input, use scanf instead of cin to avoid time limit exceed.

题目大意:求字符串中子串循环出现的最大次数

这题我最开始是把字符串切片,然后一个一个统计,如果大于之前的次数就更新次数,但是运行超时了,也不奇怪,1000000个字母,不超时才怪。

这题主要考察的是对next数组的理解。定义一个j=i-ne[i],这个就是之前匹配的最大前缀长度。用i%j,如果能整除,说明一定能输出

参考代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include<string>
#include <iostream>
#include <cstdio>
#include<cctype>
#include <string>
#include<string.h>
using namespace std;
string s,t;
int ne[100005];
int len;
void getne()
{
int i,j;
j=-1,i=0;
ne[0]=-1;
while(i<len)
{
if(j==-1||s[i]==s[j])
{
j++;
i++;
ne[i]=j;
}
else
{
j=ne[j];
}
}
}

int main(){
while(cin>>s&&s!=".")
{
memset(ne,-1,sizeof(ne));
len=s.size();
getne();
if(len%(len-ne[len])==0)
printf("%d\n",len/(len-ne[len]));
else
printf("1\n");
}


return 0;
}