[关闭]
@Dmaxiya 2019-02-01T20:59:28.000000Z 字数 3673 阅读 1267

字符串

板子


字符串下标均从1开始

Trie/字典树(HihoCoder 1014

  1. const int maxcnt = 1000000 + 100;
  2. const int Size = 30;
  3. // maxcnt 为树的节点总数,cnt 为当前节点总数
  4. // 节点下标范围为[1,cnt],root为1
  5. struct Trie {
  6. int root, cnt;
  7. int tree[maxcnt][Size];
  8. int val[maxcnt];
  9. int create() {
  10. ++cnt;
  11. memset(tree[cnt], 0, sizeof(tree[cnt]));
  12. val[cnt] = 0;
  13. return cnt;
  14. }
  15. void Init() {
  16. cnt = 0;
  17. root = create();
  18. }
  19. inline int id(const char &ch) {
  20. return ch - 'a';
  21. }
  22. void add(char *s, int v) {
  23. int pos = root;
  24. for(int i = 1; s[i]; ++i) {
  25. int w = id(s[i]);
  26. if(tree[pos][w] == 0) {
  27. tree[pos][w] = create();
  28. }
  29. pos = tree[pos][w];
  30. }
  31. val[pos] = v;
  32. }
  33. int query(char *s) {
  34. int pos = root;
  35. for(int i = 1; s[i]; ++i) {
  36. int w = id(s[i]);
  37. if(tree[pos][w] == 0) {
  38. break;
  39. }
  40. pos = tree[pos][w];
  41. }
  42. return val[pos];
  43. }
  44. };

KMP(HDU 2087

  1. const int maxn = 1000 + 100;
  2. char str1[maxn], str2[maxn];
  3. int Next[maxn];
  4. // str1 为长串,str2 为短串,Next为失配数组,maxn为字符串长度
  5. // 字符串下标从1开始
  6. void get_next(char *s) {
  7. Next[1] = 0;
  8. int j = 0;
  9. for(int i = 2; s[i]; ++i) {
  10. while(j > 0 && s[i] != s[j + 1]) {
  11. j = Next[j];
  12. }
  13. if(s[i] == s[j + 1]) {
  14. ++j;
  15. }
  16. Next[i] = j;
  17. }
  18. }
  19. int KMP(char *s1, char *s2) {
  20. int j = 0, ret = 0;
  21. for(int i = 1; s1[i]; ++i) {
  22. while(j > 0 && s1[i] != s2[j + 1]) {
  23. j = Next[j];
  24. }
  25. if(s1[i] == s2[j + 1]) {
  26. ++j;
  27. }
  28. if(s2[j + 1] == '\0') {
  29. ++ret;
  30. j = Next[j];
  31. }
  32. }
  33. return ret;
  34. }

AC 自动机(HDU 2222

  1. const int maxn = 50;
  2. const int maxlen = 21;
  3. const int maxcnt = maxn * maxlen;
  4. const int ac_size = 26;
  5. // maxcnt 为节点数量,ac_size 为每个节点的子节点数,遍历所有节点下标范围为 [0, cnt)
  6. // 其中 root = 0,队列下标范围为 [0, tail)
  7. // 添加完字符串后调用 build 函数
  8. // 创建 ac 自动机,insert 函数与 query 函数的形参字符串下标都从 0 开始
  9. struct ac_auto {
  10. int cnt, root, head, tail;
  11. int tree[maxcnt][ac_size];
  12. int fail[maxcnt], que[maxcnt];
  13. bool flag[maxcnt];
  14. int create() {
  15. memset(tree[cnt], -1, sizeof(tree[cnt]));
  16. flag[cnt] = false;
  17. ++cnt;
  18. return cnt - 1;
  19. }
  20. void Init() {
  21. cnt = 0;
  22. root = create();
  23. }
  24. int id(char ch) {
  25. return ch - 'a';
  26. }
  27. void insert(char *str) {
  28. int pos = root;
  29. for(int i = 0; str[i]; ++i) {
  30. int w = id(str[i]);
  31. if(tree[pos][w] == -1) {
  32. tree[pos][w] = create();
  33. }
  34. pos = tree[pos][w];
  35. }
  36. flag[pos] = true;
  37. }
  38. void build() {
  39. fail[root] = root;
  40. que[0] = root;
  41. head = tail = 1;
  42. for(int i = 0; i < ac_size; ++i) {
  43. if(tree[root][i] == -1) {
  44. tree[root][i] = root;
  45. } else {
  46. fail[tree[root][i]] = root;
  47. que[tail++] = tree[root][i];
  48. }
  49. }
  50. while(head != tail) {
  51. int pos = que[head++];
  52. if(flag[fail[pos]]) {
  53. flag[pos] = true;
  54. }
  55. for(int i = 0; i < ac_size; ++i) {
  56. if(tree[pos][i] == -1) {
  57. tree[pos][i] = tree[fail[pos]][i];
  58. } else {
  59. fail[tree[pos][i]] = tree[fail[pos]][i];
  60. que[tail++] = tree[pos][i];
  61. }
  62. }
  63. }
  64. }
  65. int query() {}
  66. };

后缀数组

  1. const int maxn = 4 * 50000 + 100;
  2. int sa[maxn], rankk[maxn<<1], hei[maxn];
  3. char str[maxn];
  4. // 所有数组的下标都从1 开始,maxn 为字符串长度
  5. void get_sa_hei(char *s) {
  6. static int m[maxn], tmp[maxn], w[maxn];
  7. int len = strlen(s + 1);
  8. memset(rankk, 0, sizeof(rankk[0]) * (len * 2 + 2));
  9. for(int i = 0; i <= 255; ++i) w[i] = 0;
  10. for(int i = 1; i <= len; ++i) ++w[(int)s[i]];
  11. for(int i = 1; i <= 255; ++i) w[i] += w[i - 1];
  12. for(int i = len; i > 0; --i) tmp[w[(int)s[i]]--] = i;
  13. rankk[tmp[1]] = 1;
  14. for(int i = 2; i <= len; ++i)
  15. rankk[tmp[i]] = rankk[tmp[i - 1]] + (s[tmp[i]] != s[tmp[i - 1]]);
  16. for(int k = 1; k <= len; k <<= 1) {
  17. for(int i = 0; i <= len; ++i) w[i] = 0;
  18. for(int i = 1; i <= len; ++i) ++w[rankk[i + k]];
  19. for(int i = 1; i <= len; ++i) w[i] += w[i - 1];
  20. for(int i = len; i > 0; --i) m[w[rankk[i + k]]--] = i;
  21. for(int i = 0; i <= len; ++i) w[i] = 0;
  22. for(int i = 1; i <= len; ++i) ++w[rankk[i]];
  23. for(int i = 1; i <= len; ++i) w[i] += w[i - 1];
  24. for(int i = len; i > 0; --i) tmp[w[rankk[m[i]]]--] = m[i];
  25. m[tmp[1]] = 1;
  26. for(int i = 2; i <= len; ++i)
  27. m[tmp[i]] = m[tmp[i - 1]] +
  28. (rankk[tmp[i]] != rankk[tmp[i - 1]]
  29. || rankk[tmp[i] + k] != rankk[tmp[i - 1] + k]);
  30. for(int i = 0; i <= len; ++i) rankk[i] = m[i];
  31. }
  32. for(int i = 1; i <= len; ++i) sa[rankk[i]] = i;
  33. for(int i = 1,j = 0; i <= len; ++i) {
  34. if(rankk[i] == 1) continue;
  35. for(j? --j: 0; s[sa[rankk[i] - 1] + j] == s[i + j]; ++j);
  36. hei[rankk[i]] = j;
  37. }
  38. }

Manacher

  1. const int maxn = 1000 + 100;
  2. char str[maxn];
  3. // str 下标从 1 开始,maxn 为字符串大小
  4. // P 的下标范围为 1 到 n << 1 | 1,每个中心的最长回文长度为 P[i] - 1
  5. // 输入 str 后直接调用 Manacher 返回结果
  6. int Manacher(char *s) {
  7. int n = strlen(s + 1);
  8. int len = n << 1 | 1;
  9. static char str[maxn << 1];
  10. static int P[maxn << 1];
  11. str[0] = '$';
  12. str[1] = '#';
  13. for(int i = 1; i <= n; ++i) {
  14. str[i << 1] = s[i];
  15. str[i << 1 | 1] = '#';
  16. }
  17. str[len + 1] = '\0';
  18. P[1] = 1;
  19. int ret = 0;
  20. int id = 1;
  21. int Max = 1 + P[1];
  22. for(int i = 2; i <= len; ++i) {
  23. int j = (i < Max? min(P[2 * id - i], Max - i): 1);
  24. while(str[i + j] == str[i - j]) {
  25. ++j;
  26. }
  27. P[i] = j;
  28. ret = max(ret, j - 1);
  29. if(i + P[i] > Max) {
  30. id = i;
  31. Max = i + P[i];
  32. }
  33. }
  34. return ret;
  35. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注