KMP,ACM集训

目录

                                831. KMP字符串

输入格式

输出格式

数据范围

输入样例:

输出样例:

 解析:KMP模板

                        D - Cyclic Nacklace

解析:KMP-next数组应用+循环字符串判断

                                F - Power Strings

解析:KMP-next数组应用+循环字符串判断

                                H - Count the string

 解析:next数组理解

                                J - String Problem

 解析:kmp求循环节,最小/最大表示法


                                831. KMP字符串

831. KMP字符串 - AcWing题库

给定一个字符串 S,以及一个模式串 P,所有字符串中只包含大小写英文字母以及阿拉伯数字。

模式串 P 在字符串 S 中多次作为子串出现。

求出模式串 P 在字符串 S 中所有出现的位置的起始下标。

输入格式

第一行输入整数 N,表示字符串 P 的长度。

第二行输入字符串 P。

第三行输入整数 M,表示字符串 S 的长度。

第四行输入字符串 S。

输出格式

共一行,输出所有出现位置的起始下标(下标从 00 开始计数),整数之间用空格隔开。

数据范围

1≤N≤105
1≤M≤106

输入样例:
3
aba
5
ababa
输出样例:
0 2

 解析:KMP模板

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<math.h>
#include<map>

using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N = 1e5 + 5, M = 1e6 + 5;

int n, m;
string s, p;
int ne[N];

int main() {
	cin >> n >> p >> m >> s;
	p.insert(0," ");
	s.insert(0," ");
	for (int i = 2, j = 0; i <= n; i++) {
		while (j && p[i] != p[j + 1])j = ne[j];
		if (p[i] == p[j + 1])j++;
		ne[i] = j;
	}
	for (int i = 1, j = 0; i <= m; i++) {
		while (j && s[i] != p[j + 1])j = ne[j];
		if (s[i] == p[j + 1])j++;
		if (j == n) {
			printf("%d ", i - n);
			j = ne[j];
		}
	}
	return 0;
}

                        D - Cyclic Nacklace

https://vjudge.net/contest/582298#problem/D

CC always becomes very depressed at the end of this month, he has checked his credit card yesterday, without any surprise, there are only 99.9 yuan left. he is too distressed and thinking about how to tide over the last days. Being inspired by the entrepreneurial spirit of "HDU CakeMan", he wants to sell some little things to make money. Of course, this is not an easy task.

As Christmas is around the corner, Boys are busy in choosing christmas presents to send to their girlfriends. It is believed that chain bracelet is a good choice. However, Things are not always so simple, as is known to everyone, girl's fond of the colorful decoration to make bracelet appears vivid and lively, meanwhile they want to display their mature side as college students. after CC understands the girls demands, he intends to sell the chain bracelet called CharmBracelet. The CharmBracelet is made up with colorful pearls to show girls' lively, and the most important thing is that it must be connected by a cyclic chain which means the color of pearls are cyclic connected from the left to right. And the cyclic count must be more than one. If you connect the leftmost pearl and the rightmost pearl of such chain, you can make a CharmBracelet. Just like the pictrue below, this CharmBracelet's cycle is 9 and its cyclic count is 2:


Now CC has brought in some ordinary bracelet chains, he wants to buy minimum number of pearls to make CharmBracelets so that he can save more money. but when remaking the bracelet, he can only add color pearls to the left end and right end of the chain, that is to say, adding to the middle is forbidden.
CC is satisfied with his ideas and ask you for help.

Input

The first line of the input is a single integer T ( 0 < T <= 100 ) which means the number of test cases.
Each test case contains only one line describe the original ordinary chain to be remade. Each character in the string stands for one pearl and there are 26 kinds of pearls being described by 'a' ~'z' characters. The length of the string Len: ( 3 <= Len <= 100000 ).

Output

For each case, you are required to output the minimum count of pearls added to make a CharmBracelet.

Sample

InputcopyOutputcopy
3
aaa
abca
abcde
0
2
5

解析:KMP-next数组应用+循环字符串判断

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<math.h>
#include<map>

using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N = 1e5 + 100, M = 1e4 + 5;
char str[N];
int ne[N];

int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		//memset(str, 0, sizeof(str));//千万不要加这句,加了就会WA,我也不知道为什么
		scanf("%s", str + 1);
		int len = strlen(str + 1);
		int n = len;
		for (int i = 2, j = 0; i <= n; i++) {
			while (j && str[i] != str[j + 1])j = ne[j];
			if (str[i] == str[j + 1])j++;
			ne[i] = j;
		}
		int r = len-ne[len];
		if (ne[len] == 0) {
			printf("%d\n", len);
		}
		else {
			if (len % r == 0)
				printf("0\n");
			else
				printf("%d\n", r - len % r);
		}
	}
	return 0;
}

                                F - Power Strings

Nefu字符串 - Virtual Judge (vjudge.net)

Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc" and b = "def" then a*b = "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

InputcopyOutputcopy
abcd
aaaa
ababab
.
1
4
3

Hint

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

Sponsor

解析:KMP-next数组应用+循环字符串判断

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<math.h>
#include<map>

using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N = 1e7 + 5;
int ne[N];
char str[N];

int main() {
	while (scanf("%s",  str + 1) != EOF) {
		if (str[1] == '.')
			break;
		int n = strlen(str + 1);
		for (int i = 2, j = 0; i <= n; i++) {
			while (j && str[i] != str[j + 1])j = ne[j];
			if (str[i] == str[j + 1])j++;
			ne[i] = j;
		}
		int r = n - ne[n];
		if (n % r == 0)
			printf("%d\n", n / r);
		else {
			printf("1\n");
		}
	}
	return 0;
}

                                H - Count the string

 Nefu字符串 - Virtual Judge (vjudge.net)

It is well known that AekdyCoin is good at string problems as well as number theory problems. When given a string s, we can write down all the non-empty prefixes of this string. For example:
s: "abab"
The prefixes are: "a", "ab", "aba", "abab"
For each prefix, we can count the times it matches in s. So we can see that prefix "a" matches twice, "ab" matches twice too, "aba" matches once, and "abab" matches once. Now you are asked to calculate the sum of the match times for all the prefixes. For "abab", it is 2 + 2 + 1 + 1 = 6.
The answer may be very large, so output the answer mod 10007.

Input

The first line is a single integer T, indicating the number of test cases.
For each case, the first line is an integer n (1 <= n <= 200000), which is the length of string s. A line follows giving the string s. The characters in the strings are all lower-case letters.

Output

For each case, output only one number: the sum of the match times for all the prefixes of s mod 10007.

Sample

InputcopyOutputcopy
1
4
abab
6

 解析:next数组理解

KMP中next数组的含义:0 - i 中的最大前缀后缀匹配

预处理出next数组,可知每个next数组记录该串的最大前缀的长度(数值上等价于下标)。那么对于某一个长位n的子串s,除了 它本身和模板串匹配外,还有它的最大相同后缀。
那么, ans = 本身的一个 + 最大相同后缀
关于不重不漏,由于答案的第一部分的头部都是模板串的第一个字符,对不同长度一定不同,对第二部分,末尾字符不会相同,同样不会重复

 虽然next数组统计的时最大前后缀,但大的后缀有前缀,那么大后缀中的小后缀一定也有前缀

注意:这道题中相同的部分不应该重叠,如:aaa 的答案为5

所以当前后缀相交时,此部分不计入答案。

好好理解理解!!!!

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<math.h>
#include<map>

using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N = 2e5 + 5, P = 131,mod= 10007;
int n;
char str[N];
int ne[N];

int main() {
	int T;
	scanf("%d", &T);
	while (T--) {

		scanf("%d%s",&n, str + 1);
		for (int i = 2, j = 0; i <= n; i++) {
			while (j && str[i] != str[j + 1])j = ne[j];
			if (str[i] == str[j+1])j++;
			ne[i] = j;
		}
		LL ans = 0;
		for (int i = 1; i <= n; i++) {
			if (ne[i] != 0)
				ans=(ans+1)%mod;
		}
		ans = (ans + n) % mod;
		printf("%lld\n", ans);
	}
	return 0;
}

                                J - String Problem

Nefu字符串 - Virtual Judge (vjudge.net)

Give you a string with length N, you can generate N strings by left shifts. For example let consider the string “SKYLONG”, we can generate seven strings:
String Rank
SKYLONG 1
KYLONGS 2
YLONGSK 3
LONGSKY 4
ONGSKYL 5
NGSKYLO 6
GSKYLON 7
and lexicographically first of them is GSKYLON, lexicographically last is YLONGSK, both of them appear only once.
  Your task is easy, calculate the lexicographically fisrt string’s Rank (if there are multiple answers, choose the smallest one), its times, lexicographically last string’s Rank (if there are multiple answers, choose the smallest one), and its times also.

Input

  Each line contains one line the string S with length N (N <= 1000000) formed by lower case letters.

Output

Output four integers separated by one space, lexicographically fisrt string’s Rank (if there are multiple answers, choose the smallest one), the string’s times in the N generated strings, lexicographically last string’s Rank (if there are multiple answers, choose the smallest one), and its times also.

Sample

InputcopyOutputcopy
abcder
aaaaaa
ababab
1 1 6 1
1 6 1 6
1 3 2 3

 解析:kmp求循环节,最小/最大表示法

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<math.h>
#include<map>

using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N = 1e6 + 5;

string str;
int ne[N];
int minrepresentation(string s) {
	int len = s.length();
	s = " " + s + s;
	int i = 1, j = 2;
	while (j <= len) {
		int k = 0;
		while (k < len && s[i + k] == s[j + k])k++;
		if (s[i + k] > s[j + k])i += k + 1;
		else j += k + 1;
		if (i == j)j++;
		if (i > j)swap(i, j);
	}
	return i;
}
int maxrepresentation(string s) {
	int len = s.length();
	s = " " + s + s;

	int i = 1, j = 2;
	while (j <= len) {
		int k = 0;
		while (k < len && s[i + k] == s[j + k])k++;
		if (s[i + k] < s[j + k])i += k + 1;
		else j += k + 1;
		if (i == j)j++;
		if (i > j)swap(i, j);
	}
	return i;
}
int main() {
	while (cin >> str) {
		int mn = minrepresentation(str);
		int mx = maxrepresentation(str);
		str.insert(0, " ");
		int n = str.length();
		n--;
		for (int i = 2, j = 0; i <= n; i++) {
			while (j && str[i] != str[j + 1])j = ne[j];
			if (str[i] == str[j + 1])j++;
			ne[i] = j;
		}
		int r = n - ne[n];
		int ans = n % r ? 1 : n / r;
		printf("%d %d %d %d\n", mn, ans, mx, ans);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值