KMP
剪花布条
思路
KMP算法入门题,能写出算法就基本完成
有以点需要注意,因为花布条要被剪掉,因此重复的部分不可取
如 abababac aba
abababac
aba 相互匹配减去新的字符串就是 babac ,而不要从第二位开始查找
代码
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1000000; int cnt; string s, p; int f[N]; void getf() { f[0] = -1; int i = 0, j = -1; while (i < p.size()) { if (j == -1 || p[i] == p[j]) { ++i; ++j; f[i] = j; } else j = f[j]; } } void solve() { int i = 0; int j = 0; while (i < s.size()) { if (j == -1 || s[i] == p[j]) { i++; j++; } else j = f[j]; if (j == p.size()) { cnt++; j = 0; } } } int main() { while (1) { cnt = 0; cin >> s; if (s.size() == 1 && s[0] == '#') break; cin >> p; getf(); solve(); cout << cnt << endl; } return 0; }
B - Period
思路
代码
C - Power Strings
题意
找出s字符串由多少个重复子串循环构成
思路
先求出 s 字符串的 next 数组,设 len 为 s 长度 其len-next [len ] 就是到 s 结尾循环节是多少
那么len / (len - next [len ] )就是有几个循环节 , 注意一定要len能够整除(len-next[len]),否则输出 1
代码
#include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long ll; const int N = 10000000; string s; char p[N << 1]; int f[N], len; void getf() { f[0] = -1; int i = 0, j = -1; while (i < len) { if (j == -1 || p[i] == p[j]) { i++; j++; f[i] = j; } else j = f[j]; } } int main() { while (1) { scanf("%s", p); len = strlen(p); if (p[0] == '.' && len == 1) break; getf(); if (len % (len - f[len]) == 0) { cout << len / (len - f[len]) << endl; } else cout << 1 << endl; } return 0; }
D - Oulipo
题意
给定一个单词 W 和文本 T 求 W 在 T 中出现几次
思路
求出 next 数组再遍历 T 查找就可以了,注意匹配成功时 j 的回溯
代码
#include <iostream> #include <algorithm> #include <string> using namespace std; const int N = 1000000; string s, p; int f[N], cnt; void grt_f() { int i = 0, j = -1; f[0] = -1; while (i < p.size()) { if (j == -1 || p[i] == p[j]) f[++i] = ++j; else j = f[j]; } } void solve() { int i = 0, j = 0; while (i < s.size()) { if (j == -1 || s[i] == p[j]) { i++; j++; } else j = f[j]; if (j == p.size()) { j = f[j]; cnt++; } } } int main() { ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); int T; cin >> T; while (T--) { cnt = 0; cin >> p >> s; grt_f(); solve(); cout << cnt << endl; } return 0; }
E - Seek the Name, Seek the Fame
题意
给一个字符串 S 求其所以相同前后缀的长度,以升序输出
思路
计算原字符串的hash。然后枚举长度,判断 前 len 的长度的字符串hash和后 len 长度的字符串hash
代码
#include <iostream> #include <algorithm> #include <cstring> using namespace std; const int N = 400010; string s; char p[400010]; int f[N], d[N], cnt, len; void grt_f() { int i = 0, j = -1; f[0] = -1; while (i < len) { if (j == -1 || p[i] == p[j]) f[++i] = ++j; else j = f[j]; } } void solve() { int i = 0, j = 0; while (i < s.size()) { if (j == -1 || s[i] == p[j]) { i++; j++; } else j = f[j]; if (j == len) { j = f[j]; cnt++; } } } int main() { while (scanf("%s", p)!=EOF) { len = strlen(p); cnt = 0; grt_f(); int count = 0; int t = f[len - 1]; while (t != -1) { if (p[t] == p[len - 1]) d[count++] = t + 1; t = f[t]; } for (int i = count - 1; i >= 0; i--) printf("%d ", d[i]); printf("%d\n", len); } return 0; }
总结
果然,字符串ksm不好理解,题目答案很简单,但是不好理解,对 next 数组理解不够
要多看看