A
KMP模版
#include
#include
#include
#include
#include
#include
#include
#include
#include
B
kmp魔改题,kmp匹配成功后变为失配的位置,即最长公共前后缀
#include
#include
#include
#include
#include
#include
#include
#include
#include
C
#include
#include
#include
#include
#include
#include
#include
#include
#include
D
补全循环节
f[n] && n * (n - f[n]) == 0表示存在n / (n - f[n])个循环节
若不存在,则n-f[n]为存在的最小循环节长度,我们即需要补全n - f[n] - n % (n - f[n])
#include
#include
#include
#include
#include
#include
#include
#include
#include
E
循环节
#include
#include
#include
#include
#include
#include
#include
#include
#include
G
#include
#include
#include
#include
#include
#include
#include
#include
#include
H
next数组的意义
#include
#include
#include
#include
#include
#include
#include
#include
#include
I
暴力枚举最长公共子串,用kmp判断即可
#include
#include
#include
#include
#include
#include
#include
#include
#include
J
拼接两个字符串,将两个字符串中间加入特殊字符.
#include
#include
#include
#include
#include
#include
#include
#include
#include
K
next数组计算的是子串中最长公共前后缀的长度
我们令cnt[i]表示以第i个字符结尾的所有前缀出现的次数,则cnt[i]=cnt[next[i]]+1
#include
#include
#include
#include
#include
#include
#include
#include
#include
L
原本为密文 + 明文,我们通过给出转换为-》明文 + 未知
即使用exkmp找最长前后缀
#include
#include
#include
#include
#include
#include
#include
#include
#include
M
暴力枚举子串,KMP匹配即可
#include
#include
#include
#include
#include
#include
#include
#include
#include
N
暴力KMP匹配
#include
#include
#include
#include
#include
#include
#include
#include
#include
O
能出现多少次,就要看循环节有多少个了
再就是求最大最小表示
#include
#include
#include
#include
#include
#include
#include
#include
#include
P
转换为最小表示,用set维护
#include
#include
#include
#include
#include
#include
#include
#include
#include
Q
exkmp
#include
#include
#include
#include
#include
#include
#include
#include
#include
S
exkmp去求是否为回文串,若i位置时i+ex[i]=n表示后面的串形成回文串
#include
#include
#include
#include
#include
#include
#include
#include
#include
T
分类讨论 + trie + exkmp
#include
#include
#include
using namespace std;
typedef long long LL;
const int MAXN = 2000005;
const int KIND = 26;struct TrieNode
{int num; // 到当前节点的字符串个数int cnt; // 当前节点后面回文子串个数TrieNode* nxt[26];
};TrieNode node[MAXN];
TrieNode* root; // trie树的根节点
int bg[MAXN]; // bg[i]第i+1个字符串开始的位置
int ed[MAXN]; // ed[i]第i+1个字符串结束的位置
bool flag[2][MAXN]; // flag[0][i]为true表示原串后面为回文串 flag[1][i]表示反串
char S[MAXN]; // 存放原串
char T[MAXN]; // 存放反串
int nxt[MAXN]; // 存放next数组
int extend[MAXN]; // 用于判断是否为回文子串
LL ans; // 保存结果
int tot; // node数组的下标void GetNext(char* T, int lhs, int rhs)
{int j = 0;while (lhs + j + 1 <= rhs && T[lhs + j] == T[lhs + j + 1]) ++j;nxt[lhs + 1] = j;int k = lhs + 1;for (int i = lhs + 2; i <= rhs; ++i){int p = nxt[k] + k - 1;int L = nxt[lhs + i - k];if (L + i < p + 1) nxt[i] = L;else{j = max(0, p - i + 1);while (i + j <= rhs && T[lhs + j] == T[i + j]) ++j;nxt[i] = j;k = i;}}
}void ExtendKMP(char* S, char* T, int lhs, int rhs, bool sign)
{GetNext(T, lhs, rhs);int j = 0;while (j + lhs <= rhs && S[j + lhs] == T[j + lhs]) ++j;extend[lhs] = j;int k = lhs;for (int i = lhs + 1; i <= rhs; ++i){int p = extend[k] + k - 1;int L = nxt[lhs + i - k];if (L + i < p + 1) extend[i] = L;else{j = max(0, p - i + 1);while (i + j <= rhs && S[i + j] == T[lhs + j]) ++j;extend[i] = j;k = i;}}for (int i = lhs; i <= rhs; ++i){if (extend[i] == rhs - i + 1)flag[sign][i] = true;}
}void Insert(char S[], int lhs, int rhs)
{TrieNode* temp = root;for (int i = lhs; i <= rhs; ++i){int ch = S[i] - 'a';temp->cnt += flag[0][i]; // 更新当前节点后面回文子串的数目if (temp->nxt[ch] == NULL) temp->nxt[ch] = &node[tot++];temp = temp->nxt[ch];}++temp->num; // 更新到当前节点的字符串数目
}void Search(char S[], int lhs, int rhs)
{TrieNode* temp = root;for (int i = lhs; i <= rhs; ++i){int ch = S[i] - 'a';temp = temp->nxt[ch];if (temp == NULL) break;if ((i < rhs && flag[1][i + 1]) || i == rhs)ans += temp->num;}if (temp) ans += temp->cnt;
}int main()
{int n;while (scanf("%d", &n) != EOF){// 初始化tot = 0;ans = 0;memset(node, 0, sizeof(node));memset(flag, 0, sizeof(flag));root = &node[tot++];int l = 0;int L = 0;for (int i = 0; i < n; ++i){// 输入一组数据scanf("%d", &l);scanf("%s", S + L);// 生成反串for (int j = 0; j < l; ++j)T[L + j] = S[L + l - 1 - j];bg[i] = L;ed[i] = L + l - 1;ExtendKMP(S, T , bg[i], ed[i], 0);ExtendKMP(T, S , bg[i], ed[i], 1);Insert(S, bg[i], ed[i]);L += l;}for (int i = 0; i < n; ++i)Search(T, bg[i], ed[i]);printf("%lld\n", ans);}return 0;
}
U
Manacher算法板子
#include
#include
#include
#include
using namespace std;
const int maxn = 1000000 + 5;char str[maxn], s[maxn << 1];
int pal[maxn << 1], len;
void build() {s[0] = '@';s[1] = '#';len = strlen(str);for(int i = 0; i < len; ++i) {s[2 * i + 2] = str[i];s[2 * i + 3] = '#';}s[2 * len + 2] = '\0';
}
void manacher() {build();int mx = 0, id;len = 2 * len + 2;for(int i = 0; i < len; ++i) {if(mx > i) pal[i] = min(pal[2 * id - i], mx - i);else pal[i] = 1;for(; s[i - pal[i]] == s[i + pal[i]]; pal[i]++)if(pal[i] + i > mx) {mx = pal[i] + i;id = i;}}
}int main()
{int cas = 1;while(~scanf("%s", &str)) {if(str[0] == 'E') break;manacher();int ans = 0;for(int i = 0; i < len; ++i) {ans = max(ans, pal[i]);}printf("Case %d: %d\n", cas++, ans - 1);}
}
V
Manacher魔改题
对pal数组更新时加入递减判断条件
#include
using namespace std;
const int maxn = 100000 + 5;int f[maxn], fx[maxn << 1];
int pal[maxn << 1], n, m;
void build() {fx[0] = -1;fx[1] = 300;for(int i = 0; i < n; ++i) {fx[2 * i + 2] = f[i];fx[2 * i + 3] = 300;}
}
int manacher() {build();int mx = 0, id, ans = 0, k;m = 2 * n + 2;for(int i = 0; i < m; ++i) {if(mx > i) pal[i] = min(pal[2 * id - i], mx - i);else pal[i] = 1;k = fx[i];while(fx[i - pal[i]] == fx[i + pal[i]] && ((fx[i - pal[i]] == 300) || (fx[i - pal[i]] <= k))) {if(fx[i - pal[i]] != 300) k = fx[i - pal[i]];pal[i]++;}if(pal[i] + i > mx) {mx = pal[i] + i;id = i;}ans = max(ans, pal[i]);}return ans - 1;
}int main()
{int t;scanf("%d", &t);while(t--) {scanf("%d", &n);for(int i = 0; i < n; ++i) scanf("%d", &f[i]);if(n == 1) {printf("1\n");continue;}printf("%d\n", manacher());}
}
W
manacher
#include
using namespace std;
const int maxn = 200000 + 5;
char str[maxn], s[maxn << 1];
int pal[maxn << 1], mapp[30], n;
void build() {s[0] = '@';s[1] = '#';for(int i = 0; i < n; ++i) {s[2 * i + 2] = str[i];s[2 * i + 3] = '#';}s[2 * n + 2] = '\0';
}
void manacher() {build();int mx = 0, id;n = 2 * n + 2;for(int i = 0; i < n; ++i) {if(mx > i) pal[i] = min(pal[2 * id - i], mx - i);else pal[i] = 1;for(; s[i - pal[i]] == s[i + pal[i]]; pal[i]++)if(pal[i] + i > mx) {mx = pal[i] + i;id = i;}}
}int main()
{char tar[5];while(~scanf("%s", &tar)) {scanf("%s", &str);int now = 0, noww = 0;for(int i = tar[0] - 'a'; i + 'a' <= 'z'; ++i) {mapp[i] = now;now++;}while(now + 'a' <= 'z') {mapp[noww++] = now++;}n = strlen(str);for(int i = 0; i < n; ++i) str[i] = mapp[str[i] - 'a'] + 'a';manacher();int pos = -1, len = 0;for(int i = 0; i < n; ++i) {if(pal[i] - 1 > len) {len = pal[i] - 1;pos = i;}}if(len < 2) {puts("No solution!");continue;}int l = s[pos] == '#' ? ((pos - 3) / 2 - len / 2 + 1) : ((pos - 2) / 2 - len / 2);int r = l + len - 1;printf("%d %d\n", l, r);for(int i = l; i <= r; ++i) putchar(str[i]);puts("");}
}
Z
求给的字符串中的字串需要满足为前后缀且当中还需要出现的最长长度
#include
using namespace std;
const int maxn = 1e6 + 5;
void getFail(char* p, int m, int* f) {f[0] = 0, f[1] = 0;for(int i = 1; i < m; ++i) {int j = f[i];while(j && p[i] != p[j]) j = f[j];f[i + 1] = p[i] == p[j] ? j + 1 : 0;}
}
int find(char* t, int l, int r, char* p, int m, int* f) {getFail(p, m, f);int j = 0;for(int i = l; i < r; ++i) {while(j && p[j] != t[i]) j = f[j];if(p[j] == t[i]) j++;if(j == m) return i - m + 1;}return -1;
}
char str[maxn];
int f[maxn];
int main()
{int t;scanf("%d", &t);while(t--) {scanf("%s", &str);int n = strlen(str);getFail(str, n, f);int k = f[n], ans = 0;while(k) {if(k * 2 >= n) {k = f[k];continue;}if(find(str, k, n - k, str, k, f) != -1) {ans = k;break;}k = f[k];}printf("%d\n", ans);}
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!