专题链接
HDU 3336 Count the string
题意:
事先说好,这题数据非常弱,典型的想的比出的简单,各种错误代码都能A。
这道题的题意是让你找出所有前缀在整个字符串中的子串数量。
思路:
这里只提供所谓出题人的思路,水水过去就算了啊。
对于一个位置,如果他的next数组不是0,说明这个后缀与前缀有匹配。注意这里是后缀,而不是在整个字符串范围内。然而这个思路还是A了。
AC Code
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <string>
using namespace std;
#define each(i, n) for (int(i) = 0; (i) < (n); (i)++)
#define reach(i, n) for (int(i) = n - 1; (i) >= 0; (i)--)
#define range(i, st, en) for (int(i) = (st); (i) <= (en); (i)++)
#define rrange(i, st, en) for (int(i) = (en); (i) >= (st); (i)--)
#define fill(ary, num) memset((ary), (num), sizeof(ary));
const int maxn = 2e5 + 5;
const int mod = 10007;
char des[maxn];
int nxt[maxn];
int len;
void getNext()
{
int i = 0, j = -1;
nxt[0] = -1;
while (i < len)
if (j == -1 || des[i] == des[j])
nxt[++i] = ++j;
else
j = nxt[j];
}
int main()
{
int T;
scanf("%d", &T);
while (T--) {
scanf("%d %s", &len, des);
getNext();
int ans = len;
range(i, 1, len) if (nxt[i]) ans = (ans + 1) % mod;
printf("%d\n", ans);
}
return 0;
}
HDU 4300 Clairewd’s message
题意:
还是还是还是还是还是还还是还是求最长相同前后缀的题。
思路:
无。
AC Code
#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <iterator>
#include <map>
#include <queue>
#include <stack>
#include <string>
#include <vector>
using namespace std;
#define ll long long
#define each(i, n) for (int(i) = 0; (i) < (n); (i)++)
#define reach(i, n) for (int(i) = n - 1; (i) >= 0; (i)--)
#define range(i, st, en) for (int(i) = (st); (i) <= (en); (i)++)
#define rrange(i, st, en) for (int(i) = (en); (i) >= (st); (i)--)
#define fill(num, ary) memset((ary), (num), sizeof((ary)))
const int maxn = 1e5 + 5;
char des[maxn], table[30], retable[30];
int nxt[maxn], len;
void getNext()
{
int i = 0, j = -1;
nxt[0] = -1;
len = strlen(des);
while (i < len) {
if (j == -1 || table[des[i] - 'a'] == des[j])
nxt[++i] = ++j;
else
j = nxt[j];
}
}
int main()
{
int T;
scanf("%d", &T);
while (T--) {
scanf("%s %s", table, des);
each(i, 26) retable[table[i] - 'a'] = 'a' + i;
getNext();
int crylen = len - nxt[len];
crylen = crylen < (len + 1) / 2 ? (len + 1) / 2 : crylen;
each(i, crylen) putchar(des[i]);
each(i, crylen) putchar(retable[des[i] - 'a']);
puts("");
}
return 0;
}
HDU 1238 Substrings
题意:
找出一个最长的字符串,使得它或他的反转是每个给定字符串的连续字串。
思路:
暴力枚举。
AC Code
#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <iterator>
#include <map>
#include <queue>
#include <stack>
#include <string>
#include <vector>
using namespace std;
#define ll long long
#define each(i, n) for (int(i) = 0; (i) < (n); (i)++)
#define reach(i, n) for (int(i) = n - 1; (i) >= 0; (i)--)
#define range(i, st, en) for (int(i) = (st); (i) <= (en); (i)++)
#define rrange(i, st, en) for (int(i) = (en); (i) >= (st); (i)--)
#define fill(num, ary) memset((ary), (num), sizeof((ary)))
const int inf = 0x3f3f3f3f;
const int maxn = 1e2 + 5;
int nxt[maxn], len;
char mat[maxn][maxn], des[maxn];
void getNext(const string& des)
{
int i = 0, j = -1;
nxt[0] = -1;
len = des.length();
while (i < len) {
if (j == -1 || des[i] == des[j])
nxt[++i] = ++j;
else
j = nxt[j];
}
}
bool kmpMatch(const char* src, const string& des)
{
int i = 0, j = 0, slen = strlen(src), dlen = des.length();
getNext(des);
while (i < slen && j < dlen) {
if (j == -1 || src[i] == des[j])
i++, j++;
else
j = nxt[j];
}
return j == dlen;
}
int main()
{
int T, n;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
int min_len = inf, max_len = 0;
each(i, n) scanf("%s", mat[i]), min_len = min(min_len, (int)strlen(mat[i]));
range(l, 1, min_len) range(s, 0, min_len - l)
{
string tmp = "", rtmp;
range(i, s, s + l - 1) tmp += mat[0][i];
rtmp = string(tmp.rbegin(), tmp.rend());
bool flag = true;
range(i, 1, n - 1) if (!kmpMatch(mat[i], tmp) && !kmpMatch(mat[i], rtmp))
{
flag = false;
break;
}
if (flag)
max_len = l;
}
printf("%d\n", max_len);
}
return 0;
}
HDU 2328 Corporate Identity
题意:
还是找出最长的公共连续子串。
思路:
暴力枚举。
AC Code
#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <iterator>
#include <map>
#include <queue>
#include <stack>
#include <string>
#include <vector>
using namespace std;
#define ll long long
#define each(i, n) for (int(i) = 0; (i) < (n); (i)++)
#define reach(i, n) for (int(i) = n - 1; (i) >= 0; (i)--)
#define range(i, st, en) for (int(i) = (st); (i) <= (en); (i)++)
#define rrange(i, st, en) for (int(i) = (en); (i) >= (st); (i)--)
#define fill(num, ary) memset((ary), (num), sizeof((ary)))
const int inf = 0x3f3f3f3f;
const int maxn = 2e2 + 5;
int nxt[maxn], len;
char mat[4010][maxn], des[maxn];
void getNext(const string& des)
{
int i = 0, j = -1;
nxt[0] = -1;
len = des.length();
while (i < len) {
if (j == -1 || des[i] == des[j])
nxt[++i] = ++j;
else
j = nxt[j];
}
}
bool kmpMatch(const char* src, const string& des)
{
int i = 0, j = 0, slen = strlen(src), dlen = des.length();
getNext(des);
while (i < slen && j < dlen) {
if (j == -1 || src[i] == des[j])
i++, j++;
else
j = nxt[j];
}
return j == dlen;
}
int main()
{
int n;
while (scanf("%d", &n) != EOF && n) {
int min_len = inf;
string ans = "";
each(i, n) scanf("%s", mat[i]), min_len = min(min_len, (int)strlen(mat[i]));
range(l, 1, min_len) range(s, 0, min_len - l)
{
string tmp = "";
range(i, s, s + l - 1) tmp += mat[0][i];
if (ans.length() == tmp.length() && ans < tmp)
continue;
bool flag = true;
range(i, 1, n - 1) if (!kmpMatch(mat[i], tmp))
{
flag = false;
break;
}
if (flag)
ans = tmp;
}
if (ans.length() == 0)
puts("IDENTITY LOST");
else
cout << ans << endl;
}
return 0;
}
小结
简单说一下,KMP可以解决的问题。
- 较高效的字符串匹配
- 较高效的字符串匹配计数
- 找最短循环节
- 找最长相同前后缀
- 累积的相同前后缀记录
主要是理解了next数组,一切好说。