[关闭]
@ljt12138 2017-04-17T22:35:56.000000Z 字数 4254 阅读 837

bzoj刷题记录4.17-4.21

bzoj2806: [Ctsc2012]Cheat

ctsc神题....之前的代码其实是O(n2lgn)的活该tle...

二分答案,用后缀自动机判断是否出现,然后dp。

对于任一一个位置i,以其结尾能匹配的位置必然成一个区间,设最小的转移位置为bi,则有:

dp[i]=max{dp[i1],(dp[j]+(ij))[j[bi,iLimit]]}

首先dp[i]=dp[i1],后面提出一些奇奇怪怪的东西,变成:

dp[i]=i+max{dp[j]j|j[bi,iLimit]}

由于biiLimit都是单调不减的,因此可以用单调队列维护,总复杂度O(nlgn)。然而我自带大常数,居然擦时限过...

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 2500005*2;
  4. int chl[MAXN*2][3], fa[MAXN*2], maxl[MAXN*2], root = 1, top = 1, last = 1;
  5. void push(int x)
  6. {
  7. int np = ++top, p = last; maxl[np] = maxl[p]+1;
  8. while (p && !chl[p][x]) chl[p][x] = np, p = fa[p];
  9. if (!p) fa[np] = root;
  10. else {
  11. int q = chl[p][x];
  12. if (maxl[q] == maxl[p]+1) fa[np] = q;
  13. else {
  14. int nq = ++top; maxl[nq] = maxl[p]+1;
  15. chl[nq][0] = chl[q][0], chl[nq][1] = chl[q][1];
  16. fa[nq] = fa[q], fa[q] = fa[np] = nq;
  17. while (p && chl[p][x] == q) chl[p][x] = nq, p = fa[p];
  18. }
  19. }
  20. last = np;
  21. }
  22. char str[MAXN];
  23. int dp[MAXN], max_back[MAXN];
  24. int n, m;
  25. void match(char str[], int l, int r)
  26. {
  27. if (l <= 0 || l > r) return;
  28. int nd = root, ans = 0, len = 0;
  29. for (int i = l; i <= r; i++) {
  30. int x = str[i]-'0';
  31. if (chl[nd][x]) nd = chl[nd][x], len++;
  32. else {
  33. while (nd && !chl[nd][x]) nd = fa[nd];
  34. if (!nd) nd = root, len = 0;
  35. else len = maxl[nd]+1, nd = chl[nd][x];
  36. }
  37. ans = max(ans, len);
  38. max_back[i] = i-len;
  39. }
  40. }
  41. int deq[MAXN], head, tail;
  42. bool do_dp(int L)
  43. {
  44. int l = strlen(str+1);
  45. head = 1, tail = 0;
  46. for (int i = 1; i <= l; i++) {
  47. dp[i] = dp[i-1];
  48. int p = i-L;
  49. if (p >= 0) {
  50. while (head <= tail && dp[deq[tail]]-deq[tail] < dp[p]-p) tail--;
  51. deq[++tail] = p;
  52. }
  53. while (head <= tail && deq[head] < max_back[i]) head++;
  54. if (head <= tail) dp[i] = max(dp[i], i+dp[deq[head]]-deq[head]);
  55. }
  56. return dp[l]*10 >= l*9;
  57. }
  58. int main()
  59. {
  60. scanf("%d%d", &n, &m);
  61. for (int i = 1; i <= m; i++) {
  62. scanf("%s", str);
  63. for (char *p = str; *p != '\0'; p++)
  64. push(*p-'0');
  65. push(2);
  66. }
  67. for (int i = 1; i <= n; i++) {
  68. scanf("%s", str+1);
  69. memset(max_back, 0, sizeof max_back);
  70. match(str, 1, strlen(str+1));
  71. int l = 1, r = strlen(str+1), mid;
  72. while (l <= r) {
  73. mid = (l+r)>>1;
  74. if (do_dp(mid)) l = mid+1;
  75. else r = mid-1;
  76. }
  77. printf("%d\n", l-1);
  78. }
  79. return 0;
  80. }

bzoj4310: 跳蚤

又一道神题...
大爷题解传送门:http://www.cnblogs.com/joyouth/p/5352813.html

看完豁然开朗...

kth函数的那套理论总是忘...这次复习一个.

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 200100*2;
  4. int chl[MAXN][26], fa[MAXN], maxl[MAXN];
  5. long long way[MAXN];
  6. int top = 1, root = 1, last = 1;
  7. void push(int x)
  8. {
  9. int p = last, np = ++top; maxl[np] = maxl[p] + 1;
  10. while (p && !chl[p][x]) chl[p][x] = np, p = fa[p];
  11. if (!p) fa[np] = root;
  12. else {
  13. int q = chl[p][x];
  14. if (maxl[q] == maxl[p] + 1) fa[np] = q;
  15. else {
  16. int nq = ++top; maxl[nq] = maxl[p]+1;
  17. memcpy(chl[nq], chl[q], sizeof chl[q]);
  18. fa[nq] = fa[q], fa[q] = fa[np] = nq;
  19. while (p && chl[p][x] == q) chl[p][x] = nq, p = fa[p];
  20. }
  21. }
  22. last = np;
  23. }
  24. long long dfs(int nd)
  25. {
  26. if (!nd) return 0;
  27. if (way[nd] != -1) return way[nd];
  28. way[nd] = 1;
  29. for (int i = 0; i < 26; i++)
  30. way[nd] += dfs(chl[nd][i]);
  31. return way[nd];
  32. }
  33. int vis[MAXN];
  34. void display(int nd)
  35. {
  36. if (!nd || vis[nd]) return;
  37. vis[nd] = 1;
  38. printf("--%d-- : fa = %d, maxl = %d, way = %d\n", nd, fa[nd], maxl[nd], dfs(nd));
  39. for (int i = 0; i < 26; i++)
  40. if (chl[nd][i])
  41. printf("+%c-->%d ", i+'a', chl[nd][i]);
  42. puts("");
  43. for (int i = 0; i < 26; i++)
  44. display(chl[nd][i]);
  45. }
  46. int n, k;
  47. char str[MAXN];
  48. void kth(int str[], long long k, int &top)
  49. {
  50. int nd = root, t = 0; top = 0;
  51. while (1) {
  52. for (int i = 0; i < 26; i++) {
  53. if ((t = chl[nd][i]) == 0) continue;
  54. if (k > dfs(t)) k -= dfs(t); // 整个略过
  55. else {
  56. nd = t, k--; // 去掉仅选择这个字母
  57. str[++top] = i;
  58. if (k == 0) return; // 如果结束
  59. break;
  60. }
  61. }
  62. }
  63. }
  64. int s[MAXN];
  65. unsigned long long hash_tab[MAXN], bas = 31, power[MAXN];
  66. unsigned long long hash_val(unsigned long long hash_tab[], int l, int r)
  67. {
  68. return hash_tab[r]-hash_tab[l-1]*power[r-l+1];
  69. }
  70. unsigned long long hash_T[MAXN];
  71. int strcmp_hash(int i, int j, int top)
  72. {
  73. int l = 1, r = min(j-i+1, top), mid;
  74. while (l <= r) {
  75. mid = (l+r)>>1;
  76. if (hash_val(hash_tab, i, i+mid-1) == hash_val(hash_T, 1, mid)) l = mid+1;
  77. else r = mid-1;
  78. }
  79. if (l > min(j-i+1, top)) { return j-i+1<=top; }
  80. return str[i+l-1] < s[l]+'a';
  81. }
  82. bool judge(long long k, int lim)
  83. {
  84. int top;
  85. kth(s, k, top);
  86. for (int i = 1; i <= top; i++) hash_T[i] = hash_T[i-1]*bas+s[i];
  87. int last_end = strlen(str+1), cnt = 1;
  88. for (int j = strlen(str+1); j >= 1; j--) {
  89. if (strcmp_hash(j, last_end, top)) continue;
  90. else if (strcmp_hash(j,j,top)) last_end = j, cnt++;
  91. else return 0;
  92. }
  93. return cnt <= lim;
  94. }
  95. int main()
  96. {
  97. memset(vis, 0, sizeof vis);
  98. memset(way, -1, sizeof way); // 包括空串的总状态数
  99. scanf("%d", &k);
  100. scanf("%s", str+1);
  101. power[0] = 1;
  102. int l = strlen(str+1);
  103. for (int i = 1; i <= l; i++) power[i] = power[i-1]*bas;
  104. for (int i = 1; i <= l; i++)
  105. hash_tab[i] = hash_tab[i-1]*bas+(str[i]-'a');
  106. for (char *p = str+1; *p != '\0'; ++p)
  107. push(*p-'a');
  108. long long lp = 1, rp = dfs(root)-1, mid;
  109. while (lp <= rp) {
  110. mid = (lp+rp)>>1;
  111. if (judge(mid, k)) rp = mid-1;
  112. else lp = mid+1;
  113. }
  114. int top;
  115. kth(s, rp+1, top);
  116. for (int i = 1; i <= top; i++)
  117. putchar(s[i]+'a');
  118. puts("");
  119. return 0;
  120. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注