[关闭]
@ljt12138 2017-07-02T19:52:22.000000Z 字数 29642 阅读 806

各种OJ刷题记录6.27-7.6


6175. 「美团 CodeM 初赛 Round B」黑白树

之前一道题的增强版...

考虑所有都相等,则可以从深度由深到浅贪心,如果还没有被覆盖就从这个节点覆盖上去。

但对于不同是有反例的:

http://blog.csdn.net/mengxiang000000/article/details/73718867

考虑先用一边dfs记录子树中覆盖当前节点最浅到哪里,计为。考虑到一个未被覆盖的节点时,覆盖掉中所有的节点,并即可。

没太看懂神犇们的高端写法...只好大力树剖+树状数组维护了。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 100005;
  4. struct node {
  5. int to, next;
  6. } edge[MAXN];
  7. int head[MAXN], top = 0;
  8. inline void push(int i, int j)
  9. { edge[++top] = (node) {j, head[i]}, head[i] = top; }
  10. int siz[MAXN], id[MAXN], ind[MAXN], id_in_ds = 0;
  11. int c[MAXN];
  12. int n;
  13. int ki[MAXN];
  14. int depth[MAXN], fa[MAXN][20];
  15. int low_dep[MAXN];
  16. int dfn[MAXN], dfn_top = 0;
  17. inline int lowbit(int i)
  18. { return i&(-i); }
  19. void modify(int i, int dt)
  20. {
  21. for (; i <= n; i += lowbit(i))
  22. c[i] += dt;
  23. }
  24. void cover(int i, int j)
  25. { modify(i, 1), modify(j+1, -1); }
  26. int dat(int i)
  27. {
  28. int ans = 0;
  29. for (; i; i -= lowbit(i))
  30. ans += c[i];
  31. return ans;
  32. }
  33. int kth_ans(int nd, int k)
  34. {
  35. if (k >= depth[nd]) k = depth[nd];
  36. for (register int i = 0; i < 20; i++)
  37. if (k&(1<<i))
  38. nd = fa[nd][i];
  39. return nd;
  40. }
  41. void dfs_init(int nd)
  42. {
  43. siz[nd] = 1;
  44. for (register int i = 1; i < 20; i++)
  45. fa[nd][i] = fa[fa[nd][i-1]][i-1];
  46. low_dep[nd] = kth_ans(nd, ki[nd]-1);
  47. for (int i = head[nd]; i; i = edge[i].next) {
  48. depth[edge[i].to] = depth[nd]+1;
  49. dfs_init(edge[i].to), siz[nd] += siz[edge[i].to];
  50. if (depth[low_dep[edge[i].to]] < depth[low_dep[nd]])
  51. low_dep[nd] = low_dep[edge[i].to];
  52. }
  53. dfn[++dfn_top] = nd;
  54. }
  55. inline bool cmp(int a, int b)
  56. { return depth[a] > depth[b]; }
  57. void dfs_build(int nd, int from)
  58. {
  59. id[nd] = ++id_in_ds, ind[nd] = from;
  60. int hev = -1;
  61. for (int i = head[nd]; i; i = edge[i].next) {
  62. int to = edge[i].to;
  63. if (hev == -1 || siz[to] > siz[hev]) hev = to;
  64. }
  65. if (hev == -1) return;
  66. dfs_build(hev, from);
  67. for (int i = head[nd]; i; i = edge[i].next) {
  68. int to = edge[i].to;
  69. if (to != hev) dfs_build(to, to);
  70. }
  71. }
  72. void cover_point(int nd, int pt)
  73. {
  74. while (depth[ind[nd]] > depth[pt]) {
  75. cover(id[ind[nd]], id[nd]);
  76. nd = fa[ind[nd]][0];
  77. }
  78. if (depth[nd] >= depth[pt]) cover(id[pt], id[nd]);
  79. }
  80. int main()
  81. {
  82. scanf("%d", &n);
  83. for (int i = 2; i <= n; i++)
  84. scanf("%d", &fa[i][0]), push(fa[i][0], i);
  85. for (int i = 1; i <= n; i++) scanf("%d", &ki[i]);
  86. dfs_init(1);
  87. dfs_build(1, 1);
  88. int cnt = 0;
  89. for (int i = 1; i <= n; i++) {
  90. int pt = dfn[i];
  91. if (dat(id[pt]) != 0) continue;
  92. int anc = low_dep[pt];
  93. cover_point(pt, anc), cnt++;
  94. }
  95. printf("%d\n", cnt);
  96. return 0;
  97. }

loj#112. 三维偏序

填坑...

不知道为什么印象特别深刻去年一次NOIP模拟赛建出二维数点模型,然后Too Naive,并不会做...一直向转化成逆序对...学习了一个偏序那套理论才知道Too Simple..

经典题,一维排序,二维归并,三维树状数组。

注意check一下相同的情况。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. inline int read()
  4. {
  5. int a = 0, c;
  6. do c = getchar(); while(!isdigit(c));
  7. while (isdigit(c)) {
  8. a = a*10+c-'0';
  9. c = getchar();
  10. }
  11. return a;
  12. }
  13. const int MAXN = 100005;
  14. struct pt {
  15. int x, y, z, id;
  16. } pts[MAXN], tmp[MAXN];
  17. int n, k;
  18. inline bool cmp_x(const pt &a, const pt &b)
  19. { return a.x < b.x; }
  20. inline bool cmp_y(const pt &a, const pt &b)
  21. { return a.y < b.y; }
  22. int ans[MAXN];
  23. int c[MAXN*2];
  24. inline int lowbit(int i)
  25. { return i&(-i); }
  26. void modify(int i, int dt)
  27. {
  28. for (; i <= k; i += lowbit(i))
  29. c[i] += dt;
  30. }
  31. int sum(int i)
  32. {
  33. int ans = 0;
  34. for (; i; i -= lowbit(i))
  35. ans += c[i];
  36. return ans;
  37. }
  38. void solve(int l, int r, int L, int R)
  39. {
  40. if (l >= r) return;
  41. L = pts[l].x, R = pts[r].x;
  42. if (L == R) {
  43. sort(pts+l, pts+r+1, cmp_y);
  44. int lp = l, rp = l;
  45. while (lp <= r) {
  46. while (rp+1 <= r && pts[rp+1].y == pts[lp].y) rp++;
  47. for (int i = lp; i <= rp; i++)
  48. modify(pts[i].z, 1);
  49. for (int i = lp; i <= rp; i++)
  50. ans[pts[i].id] += sum(pts[i].z)-1;
  51. lp = rp = rp+1;
  52. }
  53. for (int i = l; i <= r; i++) modify(pts[i].z, -1);
  54. return;
  55. }
  56. int MID = (L+R)>>1;
  57. int lp = l, rp = r;
  58. for (int i = l; i <= r; i++) {
  59. if (pts[i].x <= MID) tmp[lp++] = pts[i];
  60. else tmp[rp--] = pts[i];
  61. }
  62. int mid = lp-1;
  63. for (int i = l; i <= r; i++)
  64. pts[i] = tmp[i];
  65. solve(l, mid, L, MID), solve(mid+1, r, MID+1, R);
  66. lp = l, rp = mid+1;
  67. int tmp_l = l;
  68. while (lp <= mid && rp <= r) {
  69. if (pts[lp].y <= pts[rp].y) {
  70. modify(pts[lp].z, 1);
  71. tmp[tmp_l++] = pts[lp++];
  72. } else {
  73. ans[pts[rp].id] += sum(pts[rp].z);
  74. tmp[tmp_l++] = pts[rp++];
  75. }
  76. }
  77. while (lp <= mid) {
  78. modify(pts[lp].z, 1);
  79. tmp[tmp_l++] = pts[lp++];
  80. }
  81. while (rp <= r) {
  82. ans[pts[rp].id] += sum(pts[rp].z);
  83. tmp[tmp_l++] = pts[rp++];
  84. }
  85. for (int i = l; i <= mid; i++) modify(pts[i].z, -1);
  86. for (int i = l; i <= r; i++) pts[i] = tmp[i];
  87. }
  88. int d[MAXN];
  89. int main()
  90. {
  91. scanf("%d%d", &n, &k);
  92. for (int i = 1; i <= n; i++)
  93. pts[i].x = read(), pts[i].y = read(), pts[i].z = read(), pts[i].id = i;
  94. sort(pts+1, pts+n+1, cmp_x);
  95. solve(1, n, 1, k);
  96. for (int i = 1; i <= n; i++)
  97. d[ans[i]]++;
  98. for (int i = 0; i < n; i++)
  99. printf("%d\n", d[i]);
  100. return 0;
  101. }

NOIP2016 天天爱跑步

填一下这个坑....

考虑向上的路径,一个观测点观测到的条件是:

也就是。因而一个向上的路径的贡献就是其路径上为定值的点。可以在打一个标记,打一个标记。反过来看,对于一个观测点,查询的其实就是子树中所有标记个数减去标记个数。这可以用序+可持久化数组来维护,后者可以使用可持久化线段树或者可持久化平衡树实现(rope也可以),复杂度,理论能拿到95分,然而在Cogs只80...后面还是RE...

  1. #include <bits/stdc++.h>
  2. #include <ext/rope>
  3. using namespace __gnu_cxx;
  4. using namespace std;
  5. const int MAXN = 300005;
  6. struct node {
  7. int to, next;
  8. } edge[MAXN*2];
  9. int head[MAXN], top = 0;
  10. inline void push(int i, int j)
  11. { edge[++top] = (node){j, head[i]}, head[i] = top; }
  12. int depth[MAXN], W[MAXN];
  13. int u[MAXN*2], v[MAXN*2], id[MAXN*2];
  14. int n, m;
  15. int lca[MAXN], vis[MAXN];
  16. int fa[MAXN], father[MAXN], ans[MAXN];
  17. inline int findf(int nd)
  18. { return fa[nd]?fa[nd]=findf(fa[nd]):nd; }
  19. inline int read()
  20. {
  21. int a = 0, c;
  22. do c = getchar(); while(!isdigit(c));
  23. while (isdigit(c)) {
  24. a = a*10+c-'0';
  25. c = getchar();
  26. }
  27. return a;
  28. }
  29. vector<int> pt[MAXN];
  30. struct tag {
  31. int dat;
  32. int tp;
  33. };
  34. vector<tag> tag_up[MAXN], tag_down[MAXN];
  35. void dfs_init(int nd, int f)
  36. {
  37. vis[nd] = 1, father[nd] = f;
  38. for (vector<int>::iterator i = pt[nd].begin(); i != pt[nd].end(); ++i)
  39. if (vis[v[*i]]) {
  40. lca[id[*i]] = findf(v[*i]);
  41. }
  42. for (int i = head[nd]; i; i = edge[i].next) {
  43. int to = edge[i].to;
  44. if (to == f) continue;
  45. depth[to] = depth[nd]+1, dfs_init(to, nd);
  46. }
  47. fa[nd] = f;
  48. }
  49. void put_tag()
  50. {
  51. for (int i = 1; i <= m; i++) {
  52. int c = lca[i], s = u[i], t = v[i];
  53. if (c == t) {
  54. tag_up[s].push_back((tag){depth[s], 1});
  55. tag_up[father[c]].push_back((tag){depth[s], -1});
  56. } else if (c == s) {
  57. tag_down[t].push_back((tag){-depth[s], 1});
  58. tag_down[father[c]].push_back((tag){-depth[s], -1});
  59. } else {
  60. tag_up[s].push_back((tag){depth[s], 1});
  61. tag_up[father[c]].push_back((tag){depth[s], -1});
  62. int beg = depth[s]-depth[c];
  63. tag_down[t].push_back((tag){beg-depth[c], 1});
  64. tag_down[c].push_back((tag){beg-depth[c], -1});
  65. }
  66. }
  67. }
  68. int dfn[MAXN], dfn_top = 0, out[MAXN];
  69. struct my_array {
  70. rope<int> *arr[MAXN];
  71. int range_l, range_r, lev;
  72. void build()
  73. {
  74. arr[0] = new rope<int>;
  75. lev = 0;
  76. for (int i = range_l; i <= range_r; i++)
  77. arr[0]->push_back(0);
  78. }
  79. inline void new_lev()
  80. { ++lev, arr[lev] = new rope<int>(*arr[lev-1]); }
  81. inline void add_pos(int pos, int dt)
  82. {
  83. pos = pos-range_l;
  84. int dat = arr[lev]->at(pos)+dt;
  85. arr[lev]->replace(pos, dat);
  86. }
  87. inline int segment_sum(int l, int r, int pos)
  88. { return arr[r]->at(pos-range_l)-arr[l-1]->at(pos-range_l); }
  89. } arr_up, arr_down;
  90. void dfs_travel(int nd)
  91. {
  92. dfn[nd] = ++dfn_top;
  93. arr_up.new_lev(), arr_down.new_lev();
  94. for (register vector<tag>::iterator i = tag_up[nd].begin(); i != tag_up[nd].end(); ++i)
  95. arr_up.add_pos(i->dat, i->tp);
  96. for (register vector<tag>::iterator i = tag_down[nd].begin(); i != tag_down[nd].end(); ++i)
  97. arr_down.add_pos(i->dat, i->tp);
  98. for (register int i = head[nd]; i; i = edge[i].next)
  99. if (edge[i].to != father[nd]) dfs_travel(edge[i].to);
  100. out[nd] = dfn_top;
  101. }
  102. int main()
  103. {
  104. freopen("runninga.in", "r", stdin);
  105. freopen("runninga.out", "w", stdout);
  106. int size = 128 << 20;
  107. char *p = (char*)malloc(size) + size;
  108. __asm__("movl %0, %%esp\n" :: "r"(p));
  109. n = read(), m = read();
  110. for (register int i = 1; i < n; i++) {
  111. int x = read(), y = read();
  112. push(x, y), push(y, x);
  113. }
  114. for (register int i = 1; i <= n; i++) W[i] = read();
  115. for (register int i = 1; i <= m; i++) {
  116. u[i] = read(), v[i] = read();
  117. u[m+i] = v[i], v[m+i] = u[i], id[m+i] = id[i] = i;
  118. pt[u[i]].push_back(i), pt[v[i]].push_back(i+m);
  119. }
  120. dfs_init(1, 0);
  121. put_tag();
  122. arr_up.range_l = 0, arr_up.range_r = 2*n+1, arr_down.range_l = -n-1, arr_down.range_r = n+1;
  123. arr_up.build(), arr_down.build();
  124. dfs_travel(1);
  125. for (register int i = 1; i <= n; i++) {
  126. ans[i] += arr_up.segment_sum(dfn[i], out[i], depth[i]+W[i]);
  127. ans[i] += arr_down.segment_sum(dfn[i], out[i], W[i]-depth[i]);
  128. }
  129. for (register int i = 1; i <= n; i++)
  130. printf("%d ", ans[i]);
  131. puts("");
  132. return 0;
  133. }

然而这题就是典型“会的越多得分越低”型题目...这个可持久化维护的特别鸡肋。由于答案具有可减性,我们在dfs的过程中维护一个数组,进入时记录一下答案,退出时记录一下,差值就是所求了...

  1. #include <bits/stdc++.h>
  2. #include <ext/rope>
  3. using namespace __gnu_cxx;
  4. using namespace std;
  5. const int MAXN = 300005;
  6. struct node {
  7. int to, next;
  8. } edge[MAXN*2];
  9. int head[MAXN], top = 0;
  10. inline void push(int i, int j)
  11. { edge[++top] = (node){j, head[i]}, head[i] = top; }
  12. int depth[MAXN], W[MAXN];
  13. int u[MAXN*2], v[MAXN*2], id[MAXN*2];
  14. int n, m;
  15. int lca[MAXN], vis[MAXN];
  16. int fa[MAXN], father[MAXN], ans[MAXN];
  17. inline int findf(int nd)
  18. { return fa[nd]?fa[nd]=findf(fa[nd]):nd; }
  19. inline int read()
  20. {
  21. int a = 0, c;
  22. do c = getchar(); while(!isdigit(c));
  23. while (isdigit(c)) {
  24. a = a*10+c-'0';
  25. c = getchar();
  26. }
  27. return a;
  28. }
  29. vector<int> pt[MAXN];
  30. struct tag {
  31. int dat;
  32. int tp;
  33. };
  34. vector<tag> tag_up[MAXN], tag_down[MAXN];
  35. void dfs_init(int nd, int f)
  36. {
  37. vis[nd] = 1, father[nd] = f;
  38. for (vector<int>::iterator i = pt[nd].begin(); i != pt[nd].end(); ++i)
  39. if (vis[v[*i]]) {
  40. //cerr << *i << " " << id[*i] << " " << v[*i] << endl;
  41. lca[id[*i]] = findf(v[*i]);
  42. }
  43. for (int i = head[nd]; i; i = edge[i].next) {
  44. int to = edge[i].to;
  45. if (to == f) continue;
  46. depth[to] = depth[nd]+1, dfs_init(to, nd);
  47. }
  48. fa[nd] = f;
  49. }
  50. void put_tag()
  51. {
  52. for (int i = 1; i <= m; i++) {
  53. int c = lca[i], s = u[i], t = v[i];
  54. // cerr << "LCA(" << s << "," << t << ") = " << c << endl;
  55. if (c == t) {
  56. tag_up[s].push_back((tag){depth[s], 1});
  57. tag_up[father[c]].push_back((tag){depth[s], -1});
  58. } else if (c == s) {
  59. tag_down[t].push_back((tag){-depth[s], 1});
  60. tag_down[father[c]].push_back((tag){-depth[s], -1});
  61. } else {
  62. tag_up[s].push_back((tag){depth[s], 1});
  63. tag_up[father[c]].push_back((tag){depth[s], -1});
  64. int beg = depth[s]-depth[c];
  65. tag_down[t].push_back((tag){beg-depth[c], 1});
  66. tag_down[c].push_back((tag){beg-depth[c], -1});
  67. }
  68. }
  69. }
  70. int arr_up[MAXN*4], arr_down[MAXN*4], beg = 600000;
  71. void dfs_travel(int nd)
  72. {
  73. int pre = arr_up[depth[nd]+W[nd]+beg] + arr_down[W[nd]-depth[nd]+beg];
  74. for (register int i = head[nd]; i; i = edge[i].next)
  75. if (edge[i].to != father[nd]) dfs_travel(edge[i].to);
  76. for (register vector<tag>::iterator i = tag_up[nd].begin(); i != tag_up[nd].end(); ++i)
  77. arr_up[i->dat+beg] += i->tp;
  78. for (register vector<tag>::iterator i = tag_down[nd].begin(); i != tag_down[nd].end(); ++i)
  79. arr_down[i->dat+beg] += i->tp;
  80. ans[nd] = arr_up[depth[nd]+W[nd]+beg] + arr_down[W[nd]-depth[nd]+beg]-pre;
  81. }
  82. int main()
  83. {
  84. n = read(), m = read();
  85. for (register int i = 1; i < n; i++) {
  86. int x = read(), y = read();
  87. push(x, y), push(y, x);
  88. }
  89. for (register int i = 1; i <= n; i++) W[i] = read();
  90. for (register int i = 1; i <= m; i++) {
  91. u[i] = read(), v[i] = read();
  92. u[m+i] = v[i], v[m+i] = u[i], id[m+i] = id[i] = i;
  93. pt[u[i]].push_back(i), pt[v[i]].push_back(i+m);
  94. }
  95. dfs_init(1, 0);
  96. put_tag();
  97. dfs_travel(1);
  98. for (register int i = 1; i <= n; i++)
  99. printf("%d ", ans[i]);
  100. puts("");
  101. return 0;
  102. }

NOIP2015 运输计划

继续填古代坑计划...

当时用SPFA水了25...

现在看来很水啊..二分后随便树剖就行了。也可以树上差分搞。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 300005;
  4. struct node {
  5. int to, next, dis;
  6. } edge[MAXN*2];
  7. int head[MAXN], top = 0;
  8. inline void push(int i, int j, int d)
  9. { edge[++top] = (node) {j, head[i], d}, head[i] = top; }
  10. int fa[MAXN];
  11. inline int findf(int a)
  12. { return fa[a]?fa[a] = findf(fa[a]):a; }
  13. int u[MAXN*2], v[MAXN*2], id[MAXN*2], lca[MAXN], vis[MAXN], father[MAXN];
  14. int dis[MAXN];
  15. int n, m;
  16. vector<int> pt[MAXN];
  17. int depth[MAXN], len[MAXN];
  18. inline int read()
  19. {
  20. int a = 0, c;
  21. do c = getchar(); while (!isdigit(c));
  22. while (isdigit(c)) {
  23. a = a*10+c-'0';
  24. c = getchar();
  25. }
  26. return a;
  27. }
  28. void dfs_init(int nd, int f)
  29. {
  30. vis[nd] = 1, father[nd] = f;
  31. for (vector<int>::iterator i = pt[nd].begin(); i != pt[nd].end(); ++i)
  32. if (vis[v[*i]])
  33. lca[id[*i]] = findf(v[*i]);
  34. for (int i = head[nd]; i; i = edge[i].next) {
  35. int to = edge[i].to;
  36. if (to == f) continue;
  37. depth[to] = depth[nd]+1, len[to] = len[nd]+edge[i].dis;
  38. dfs_init(to, nd);
  39. }
  40. fa[nd] = f;
  41. }
  42. int tag[MAXN], max_able = 0;
  43. void dfs_collect(int nd)
  44. {
  45. for (int i = head[nd]; i; i = edge[i].next) {
  46. int to = edge[i].to;
  47. if (to == father[nd]) continue;
  48. dfs_collect(to), tag[nd] += tag[to];
  49. }
  50. }
  51. bool check(int ans)
  52. {
  53. memset(tag, 0, sizeof tag);
  54. int max_val = 0, cnt = 0;
  55. max_able = 0;
  56. for (int i = 1; i <= m; i++)
  57. if (dis[i] > ans) {
  58. max_val = max(max_val, dis[i]);
  59. cnt++;
  60. // cerr << u[i] << " " << v[i] << " " << lca[i] << endl;
  61. tag[u[i]]++, tag[v[i]]++, tag[father[lca[i]]]--, tag[lca[i]]--;
  62. }
  63. if (cnt == 0) return 1;
  64. //cerr << cnt << endl;
  65. dfs_collect(1);
  66. for (int i = 1; i <= n; i++) {
  67. if (tag[i] != cnt) continue;
  68. //cerr << tag[i] << endl;
  69. for (int j = head[i]; j; j = edge[j].next) {
  70. int to = edge[j].to;
  71. // if (to == father[i]) continue;
  72. if (tag[to] == cnt)
  73. max_able = max(max_able, edge[j].dis);
  74. }
  75. }
  76. //cerr << max_val << " " << max_able << " " << ans << endl;
  77. return max_val-max_able <= ans;
  78. }
  79. int main()
  80. {
  81. //freopen("transport.in", "r", stdin);
  82. //freopen("transport.out", "w", stdout);
  83. n = read(), m = read();
  84. for (int i = 1; i < n; i++) {
  85. int l = read(), r = read(), d = read();
  86. push(l, r, d), push(r, l, d);
  87. }
  88. for (int i = 1; i <= m; i++) {
  89. u[i] = read(), v[i] = read();
  90. v[i+m] = u[i], u[i+m] = v[i], id[i] = id[i+m] = i;
  91. pt[u[i]].push_back(i), pt[v[i]].push_back(i+m);
  92. }
  93. dfs_init(1, 0);
  94. for (int i = 1; i <= m; i++)
  95. dis[i] = len[u[i]]+len[v[i]]-len[lca[i]]*2;
  96. int l = 0, r = 300000ll*1000, mid;
  97. while (l <= r) {
  98. mid = (l+r)>>1;
  99. if (check(mid)) r = mid-1;
  100. else l = mid+1;
  101. }
  102. printf("%d\n", r+1);
  103. return 0;
  104. }

loj#6066. 「2017 山东一轮集训 Day3」第二题

我SX....原来括号序列就是dfs序啊..

二分答案,维护括号序列hash,考虑对于节点,以其为根的子树恰好被删去即是在其个祖先处,打一个标记,然后对于每个节点大力计算就好了。复杂度,如果祖先用长链剖分、排序用基数排序,可以做到

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 100005;
  4. struct node {
  5. int to, next;
  6. } edge[MAXN];
  7. int head[MAXN], top = 0;
  8. void push(int i, int j)
  9. { edge[++top] = (node) {j, head[i]}, head[i] = top; }
  10. int hash_dat[MAXN*2], dfn_top = 0;
  11. vector<pair<int, int> > forbidden[MAXN];
  12. int fa[MAXN][20], n;
  13. int dfn_in[MAXN], dfn_out[MAXN];
  14. typedef unsigned long long ull;
  15. ull hash_tab[MAXN*2], bs = 19260817, power[MAXN*2];
  16. int height[MAXN];
  17. // --- hash ---
  18. void hash_init()
  19. {
  20. power[0] = 1;
  21. for (int i = 1; i <= n*2; i++) power[i] = power[i-1]*bs;
  22. for (int i = 1; i <= n*2; i++)
  23. hash_tab[i] = hash_tab[i-1]*bs+hash_dat[i];
  24. }
  25. ull hash_val(int l, int r)
  26. { return hash_tab[r]-hash_tab[l-1]*power[r-l+1]; }
  27. // --- hash ---
  28. int kth_anc(int nd, int k)
  29. {
  30. for (int i = 0; i < 20; i++)
  31. if (k&(1<<i))
  32. nd = fa[nd][i];
  33. return nd;
  34. }
  35. void dfs_init(int nd)
  36. {
  37. height[nd] = 0;
  38. ++dfn_top, hash_dat[dfn_top] = 1;
  39. dfn_in[nd] = dfn_top;
  40. for (int i = 1; i < 20; i++)
  41. fa[nd][i] = fa[fa[nd][i-1]][i-1];
  42. for (int i = head[nd]; i; i = edge[i].next) {
  43. fa[edge[i].to][0] = nd, dfs_init(edge[i].to);
  44. height[nd] = max(height[nd], height[edge[i].to]+1);
  45. }
  46. ++dfn_top, hash_dat[dfn_top] = 2;
  47. dfn_out[nd] = dfn_top;
  48. }
  49. set<ull> st;
  50. bool calc(int k)
  51. {
  52. for (int i = 1; i <= n; i++) forbidden[i].clear();
  53. st.clear();
  54. for (int i = 1; i <= n; i++) {
  55. int nd = kth_anc(i, k+1);
  56. forbidden[nd].push_back(make_pair(dfn_in[i], dfn_out[i]));
  57. }
  58. for (int i = 1; i <= n; i++) {
  59. sort(forbidden[i].begin(), forbidden[i].end());
  60. forbidden[i].push_back(make_pair(dfn_out[i]+1, dfn_out[i]+1));
  61. }
  62. for (int i = 1; i <= n; i++) {
  63. if (height[i] < k) continue;
  64. ull hash_v = 0;
  65. int l = dfn_in[i];
  66. for (int j = 0, sz = forbidden[i].size(); j < sz; j++) {
  67. int r = forbidden[i][j].first-1;
  68. if (l <= r)
  69. hash_v = hash_v*power[r-l+1]+hash_val(l, r);
  70. l = forbidden[i][j].second+1;
  71. }
  72. if (st.count(hash_v)) return 1;
  73. st.insert(hash_v);
  74. }
  75. return 0;
  76. }
  77. inline int read()
  78. {
  79. int a = 0, c;
  80. do c = getchar(); while (!isdigit(c));
  81. while (isdigit(c)) {
  82. a = a*10+c-'0';
  83. c = getchar();
  84. }
  85. return a;
  86. }
  87. int rd[MAXN], rt;
  88. int main()
  89. {
  90. n = read();
  91. for (int i = 1; i <= n; i++) {
  92. int x, v;
  93. x = read();
  94. for (int j = 1; j <= x; j++)
  95. v = read(), push(i, v), rd[v]++;
  96. }
  97. for (int i = 1; i <= n; i++)
  98. if (rd[i] == 0) {
  99. rt = i;
  100. break;
  101. }
  102. dfs_init(rt), hash_init();
  103. int l = 0, r = n, mid;
  104. while (l <= r) {
  105. mid = (l+r)>>1;
  106. if (calc(mid)) l = mid+1;
  107. else r = mid-1;
  108. }
  109. printf("%d\n", l-1);
  110. return 0;
  111. }

loj #6173. Samjia和矩阵

这个命题思路在哪里见过....当时是kmp,现在用SAM就好了。

考虑枚举矩形的高度,则高度为的矩形可以看成以维向量为字符集的长度为的字符串。

人话就是,把一列看成一个字符。

然后就可以用广义后缀自动机大法了。由于字符集太大,需要hash+map<ull>

ps : std貌似是后缀数组,复杂度少一个,速度快到不知哪里去了...

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef unsigned long long ull;
  4. int n, m;
  5. char A[115][115];
  6. const int MAXN = 30005;
  7. const ull bas = 19260817;
  8. struct SAM {
  9. map<ull,int> chl[MAXN];
  10. int fa[MAXN], maxl[MAXN], top, root;
  11. void clear()
  12. { top = root = 1, maxl[1] = 0; }
  13. int push(int nd, ull dat)
  14. {
  15. int p = nd, np = ++top; maxl[np] = maxl[p]+1, chl[np].clear();
  16. while (p && !chl[p][dat]) chl[p][dat] = np, p = fa[p];
  17. if (!p) fa[np] = root;
  18. else {
  19. int q = chl[p][dat];
  20. if (maxl[q] == maxl[p]+1) fa[np] = q;
  21. else {
  22. int nq = ++top; chl[nq] = chl[q], maxl[nq] = maxl[p]+1;
  23. fa[nq] = fa[q], fa[q] = fa[np] = nq;
  24. while (p && chl[p][dat] == q) chl[p][dat] = nq, p = fa[p];
  25. }
  26. }
  27. return np;
  28. }
  29. } sam_main;
  30. struct trie {
  31. map<ull, int> tree[MAXN];
  32. int top, root;
  33. trie()
  34. { top = root = 1; }
  35. void clear()
  36. {
  37. for (int i = 1; i <= top; i++) tree[i].clear();
  38. top = root = 1;
  39. }
  40. void push(vector<ull> &str)
  41. {
  42. int nd = root;
  43. for (auto i : str) {
  44. if (!tree[nd].count(i)) tree[nd][i] = ++top;
  45. nd = tree[nd][i];
  46. }
  47. }
  48. } trie_main;
  49. queue<int> que;
  50. int st[MAXN];
  51. void bfs_build_sam()
  52. {
  53. sam_main.clear();
  54. que.push(trie_main.root);
  55. st[trie_main.root] = sam_main.root;
  56. while (!que.empty()) {
  57. int nd = que.front(); que.pop();
  58. for (auto i : trie_main.tree[nd]) {
  59. st[i.second] = sam_main.push(st[nd], i.first);
  60. que.push(i.second);
  61. }
  62. }
  63. }
  64. int solve()
  65. {
  66. bfs_build_sam();
  67. int ans = 0;
  68. for (int i = 2; i <= sam_main.top; i++)
  69. ans += sam_main.maxl[i]-sam_main.maxl[sam_main.fa[i]];
  70. return ans;
  71. }
  72. ull hash_val[120][120]; // i, j 第i列前j项哈希
  73. ull power[120];
  74. inline ull hash_seg(int i, int l, int r)
  75. { return hash_val[i][r]-hash_val[i][l-1]*power[r-l+1]; }
  76. int main()
  77. {
  78. scanf("%d%d", &n, &m);
  79. power[0] = 1;
  80. for (int i = 1; i <= n; i++) power[i] = power[i-1]*bas;
  81. for (int i = 1; i <= n; i++)
  82. scanf("%s", A[i]+1);
  83. for (int i = 1; i <= m; i++) {
  84. for (int j = 1; j <= n; j++)
  85. hash_val[i][j] = hash_val[i][j-1]*bas+A[j][i]-'A'+1;
  86. }
  87. vector<ull> vec;
  88. int ans = 0;
  89. for (int i = 1; i <= n; i++) {
  90. trie_main.clear();
  91. for (int j = 1; j+i-1 <= n; j++) {
  92. vec.clear();
  93. for (int k = 1; k <= m; k++)
  94. vec.push_back(hash_seg(k, j, j+i-1));
  95. trie_main.push(vec);
  96. }
  97. ans += solve();
  98. }
  99. cout << ans << endl;
  100. return 0;
  101. }

loj#2098. 「CQOI2015」多项式

看不懂神犇五行代码系列qwq...

考虑展开右边级数第项,发现:

然后就py直接做了...

  1. import math
  2. def choose(n, k):
  3. ans = 1
  4. for i in range(k):
  5. ans = ans*(n-i)
  6. for i in range(1, k+1):
  7. ans = ans/i
  8. return ans
  9. n = int(raw_input())
  10. t = int(raw_input())
  11. m = int(raw_input())
  12. def mul(a, b):
  13. c = {}
  14. for i in range(2):
  15. for j in range(2):
  16. c[i, j] = 0
  17. for k in range(2):
  18. c[i, j] = (c[i, j]+a[i, k]*b[k, j])%3389
  19. return c
  20. def power(a, n):
  21. ans = {(0,0):1, (1,1):1, (1, 0):0, (0,1):0}
  22. for i in range(10000):
  23. if (((n>>i)&1) != 0):
  24. ans = mul(ans, a)
  25. a = mul(a, a)
  26. return ans
  27. def get_A(n):
  28. c = {}
  29. c[0, 0], c[0, 1], c[1, 0], c[1, 1] = 1234, 5678, 0, 1
  30. c = power(c, n)
  31. return (c[0, 0]+c[0, 1])%3389
  32. b = {}
  33. b[0] = get_A(n)
  34. for i in range(1, 6):
  35. tmp, flag, tt = n-i, 1, t
  36. b[i] = get_A(n-i)
  37. for j in range(1, i+1):
  38. b[i] = b[i]+b[i-j]*choose(tmp+j, j)*t**j*flag
  39. flag, tt = -flag, tt*t
  40. # print(b[i])
  41. print(b[n-m])

「NOI2016」优秀的拆分

补题计划continue...

首先考场是肯定写85-95的...后面的性价比不高..

正解其实也(看过题解后)比较简单。考虑求的个数只要求出形如的结尾位置和开头位置,然后即为所求。考虑枚举的长度,并将作为关键点。对于一个方案可以转化成求两个关键点。如果,说明存在一个拆分,在对应的位置区间加1。求lcp和lcs可以用后缀数组或者二分哈希(单哈希会被卡..双哈希在uoj貌似TLE...但loj和bzoj过了)。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 100005;
  4. typedef unsigned long long ull;
  5. char str[MAXN];
  6. int n, T;
  7. ull hash_tab[MAXN], bas = 31;
  8. long long hash_tab2[MAXN], bas2 = 97, mod = 1e9+7;
  9. ull power[MAXN];
  10. long long power2[MAXN];
  11. void hash_init()
  12. {
  13. for (register int i = 1; i <= n+n; i++)
  14. hash_tab[i] = hash_tab[i-1]*bas+str[i]-'a'+1;
  15. for (register int i = 1; i <= n+n; i++)
  16. hash_tab2[i] = (hash_tab2[i-1]*bas2%mod+str[i]-'a'+1)%mod;
  17. }
  18. inline ull hash_val1(int l, int r)
  19. { return l <= r ? hash_tab[r]-hash_tab[l-1]*power[r-l+1] : 0; }
  20. inline ull hash_val2(int l, int r)
  21. { return l <= r ? ((hash_tab2[r]-hash_tab2[l-1]*power2[r-l+1]%mod)%mod+mod)%mod : 0; }
  22. int tag_after[MAXN], tag_bef[MAXN];
  23. int pos[MAXN], top = 0;
  24. int max_len_lr(int a, int b, int upp)
  25. {
  26. register int l = 0, r = upp, mid;
  27. while (l <= r) {
  28. mid = (l+r)>>1;
  29. if (hash_val1(a, a+mid-1) == hash_val1(b, b+mid-1)
  30. && hash_val2(a, a+mid-1) == hash_val2(b, b+mid-1)) l = mid+1;
  31. else r = mid-1;
  32. }
  33. return l-1;
  34. }
  35. int max_len_rl(int a, int b, int upp)
  36. {
  37. register int l = 0, r = upp, mid;
  38. while (l <= r) {
  39. mid = (l+r)>>1;
  40. if (hash_val1(a-mid+1, a) == hash_val1(b-mid+1, b)
  41. && hash_val2(a-mid+1, a) == hash_val2(b-mid+1, b)) l = mid+1;
  42. else r = mid-1;
  43. }
  44. return l-1;
  45. }
  46. int main()
  47. {
  48. scanf("%d", &T);
  49. while (T--) {
  50. scanf("%s", str+1);
  51. memset(tag_bef, 0, sizeof tag_bef);
  52. memset(tag_after, 0, sizeof tag_after);
  53. n = strlen(str+1);
  54. power[0] = power2[0] = 1;
  55. for (register int i = 1; i <= n; i++) power[i] = power[i-1]*bas;
  56. for (register int i = 1; i <= n; i++) power2[i] = power2[i-1]*bas2%mod;
  57. for (register int i = n+1; i <= n+n; i++) str[i] = int('z')+1;
  58. hash_init();
  59. for (register int i = 1; i <= n; i++) {
  60. top = 0;
  61. do {
  62. ++top, pos[top] = pos[top-1]+i;
  63. } while (pos[top] < n);
  64. register int a, b, lr, rl;
  65. for (register int j = 1; j < top; j++) {
  66. a = pos[j], b = pos[j+1];
  67. lr = max_len_lr(a, b, i), rl = max_len_rl(a, b, i);
  68. if (lr+rl-1 < i) continue;
  69. tag_after[b+i-rl]++, tag_after[b+lr]--;
  70. tag_bef[a-(i-lr)+1]--, tag_bef[a-rl+1]++;
  71. }
  72. }
  73. for (register int i = 1; i <= n+n; i++) tag_after[i] += tag_after[i-1], tag_bef[i] += tag_bef[i-1];
  74. long long ans = 0;
  75. for (register int i = 1; i <= n; i++)
  76. ans += (long long)tag_after[i]*tag_bef[i+1];
  77. printf("%lld\n", ans);
  78. }
  79. return 0;
  80. }

「NOI2016」循环之美

好神啊....感觉在考场上最多推出84...

首先打个表发现所求其实就是:

然后交换求和顺序并莫比乌斯大力算,得出:

,考虑这样一个序列:

由辗转相除法可以得出,因此这段和这段对答案的贡献是一样的。所以:

这样就可以大力拿到84了.

剩下的比较有构造性...设。如果能快速求出这个就可以喜闻乐见下底函数分块了。

考虑最小的因子,令为最大的,则考虑。则:

可知。而,因此:

大功告成...

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXK = 2005, MAXN = 1000005;
  4. const int MOD = 1000007, bas = 2333;
  5. int cnt = 0;
  6. struct hash_table {
  7. long long tab[MOD];
  8. int n[MOD], k[MOD];
  9. inline int hash_val(int n, int k)
  10. { return ((long long)n*bas%MOD+k)%MOD; }
  11. inline long long val(int __n, int __k)
  12. {
  13. int val = hash_val(__n, __k);
  14. while (n[val] != __n || k[val] != __k) (val += 1) %= MOD;
  15. return tab[val];
  16. }
  17. inline void insert(int __n, int __k, long long dat)
  18. {
  19. int val = hash_val(__n, __k);
  20. while (k[val] != 0 || n[val] != 0) val++;
  21. n[val] = __n, k[val] = __k, tab[val] = dat;
  22. }
  23. inline bool count(int __n, int __k)
  24. {
  25. int val = hash_val(__n, __k);
  26. while (n[val] != __n || k[val] != __k) {
  27. if (n[val] == 0 && k[val] == 0) return 0;
  28. val++;
  29. }
  30. return 1;
  31. }
  32. };
  33. inline int gcd(int a, int b)
  34. { return b == 0 ? a : gcd(b, a%b); }
  35. int prime[MAXN], not_prime[MAXN], mu[MAXN], top = 0;
  36. int M[MAXN];
  37. int n, m, k;
  38. int p[MAXK], q[MAXK]; // 拿出的第一个素因子; 剩余
  39. int f[MAXK];
  40. void get_prime(int n)
  41. {
  42. mu[1] = 1, not_prime[1] = 1;
  43. for (int i = 2; i <= n; i++) {
  44. if (!not_prime[i]) prime[++top] = i, mu[i] = -1;
  45. for (int j = 1; j <= top && i*prime[j] <= n; j++) {
  46. not_prime[i*prime[j]] = 1;
  47. if (i%prime[j] == 0) {
  48. mu[i*prime[j]] = 0;
  49. break;
  50. }
  51. mu[i*prime[j]] = -mu[i];
  52. }
  53. }
  54. for (int i = 1; i <= n; i++)
  55. M[i] = M[i-1]+mu[i];
  56. }
  57. hash_table hash_M;
  58. long long get_M(int N)
  59. {
  60. if (N < MAXN) return M[N];
  61. if (hash_M.count(N, 0)) return hash_M.val(N, 0);
  62. long long ans = 1;
  63. int last;
  64. for (int i = 2; i <= N; i = last+1) {
  65. last = N/(N/i);
  66. ans -= (last-i+1)*get_M(N/i);
  67. }
  68. hash_M.insert(N, 0, ans);
  69. return ans;
  70. }
  71. hash_table hash_s;
  72. long long get_G(int n, int k)
  73. {
  74. // cerr << n << " " << k << endl;
  75. if (n == 0) return 0;
  76. if (k == 1) return get_M(n);
  77. if (hash_s.count(n, k)) return cnt++, hash_s.val(n, k);
  78. long long tmp = get_G(n, q[k])+get_G(n/p[k], p[k]*q[k]);
  79. hash_s.insert(n, k, tmp);
  80. return tmp;
  81. }
  82. void init_pq()
  83. {
  84. for (int i = 2; i <= k; i++) {
  85. if (!not_prime[i]) p[i] = i, q[i] = 1;
  86. else {
  87. int fac, pp = 1;
  88. for (int j = 1; j <= top; j++)
  89. if (i%prime[j] == 0) {
  90. fac = prime[j];
  91. break;
  92. }
  93. while (i%(pp*fac) == 0) pp *= fac;
  94. p[i] = fac, q[i] = i/pp;
  95. }
  96. }
  97. }
  98. void init_f()
  99. {
  100. f[0] = 0;
  101. for (int i = 1; i <= k; i++)
  102. f[i] = f[i-1]+(gcd(i, k) == 1);
  103. }
  104. inline int get_F(int n)
  105. { return n/k*f[k]+f[n%k]; }
  106. int main()
  107. {
  108. cin >> n >> m >> k;
  109. get_prime(MAXN-1);
  110. init_pq();
  111. init_f();
  112. int last;
  113. long long ans = 0;
  114. for (register int i = 1; i <= n && i <= m; i = last+1) {
  115. last = min(min(n/(n/i), m/(m/i)), n);
  116. ans += (get_G(last, k)-get_G(i-1, k))*(n/i)*get_F(m/i);
  117. }
  118. cout << ans << endl;
  119. return 0;
  120. }

「NOI2016」区间

可能是NOI2016唯一一道水题吧......

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 500005;
  4. struct segm {
  5. int l, r, len;
  6. friend bool operator < (const segm &a, const segm &b)
  7. { return a.len < b.len; }
  8. } seg[MAXN];
  9. int n, m;
  10. int dx[MAXN*2], dx_top = 0;
  11. void dx_init()
  12. {
  13. for (int i = 1; i <= n; i++)
  14. dx[++dx_top] = seg[i].l, dx[++dx_top] = seg[i].r;
  15. sort(dx+1, dx+dx_top+1);
  16. dx_top = unique(dx+1, dx+dx_top+1)-dx-1;
  17. for (int i = 1; i <= n; i++) {
  18. seg[i].l = lower_bound(dx+1, dx+dx_top+1, seg[i].l)-dx;
  19. seg[i].r = lower_bound(dx+1, dx+dx_top+1, seg[i].r)-dx;
  20. }
  21. }
  22. int max_val[MAXN*4], lc[MAXN*4], rc[MAXN*4], l[MAXN*4], r[MAXN*4], tag[MAXN*4];
  23. int root = 0, top = 0;
  24. inline void pdw(int nd)
  25. {
  26. max_val[nd] += tag[nd];
  27. if (lc[nd]) tag[lc[nd]] += tag[nd], tag[rc[nd]] += tag[nd];
  28. tag[nd] = 0;
  29. }
  30. inline void update(int nd)
  31. { max_val[nd] = max(max_val[lc[nd]], max_val[rc[nd]]); }
  32. void build(int &nd, int opl, int opr)
  33. {
  34. nd = ++top, l[nd] = opl, r[nd] = opr;
  35. if (opl < opr)
  36. build(lc[nd], opl, (opl+opr)/2), build(rc[nd], (opl+opr)/2+1, opr);
  37. }
  38. void modify(int nd, int opl, int opr, int dt)
  39. {
  40. pdw(nd);
  41. if (l[nd] == opl && r[nd] == opr) tag[nd] += dt;
  42. else {
  43. int mid = (l[nd] + r[nd]) >> 1;
  44. if (opr <= mid) modify(lc[nd], opl, opr, dt);
  45. else if (opl > mid) modify(rc[nd], opl, opr, dt);
  46. else modify(lc[nd], opl, mid, dt), modify(rc[nd], mid+1, opr, dt);
  47. pdw(lc[nd]), pdw(rc[nd]), update(nd);
  48. }
  49. }
  50. int query(int nd, int opl, int opr)
  51. {
  52. pdw(nd);
  53. if (l[nd] == opl && r[nd] == opr) return max_val[nd];
  54. else {
  55. int mid = (l[nd] + r[nd]) >> 1;
  56. if (opr <= mid) return query(lc[nd], opl, opr);
  57. else if (opl > mid) return query(rc[nd], opl, opr);
  58. else return max(query(lc[nd], opl, mid), query(rc[nd], mid+1, opr));
  59. }
  60. }
  61. inline int read()
  62. {
  63. int a = 0, c;
  64. do c = getchar(); while (!isdigit(c));
  65. while (isdigit(c)) {
  66. a = a*10+c-'0';
  67. c = getchar();
  68. }
  69. return a;
  70. }
  71. int main()
  72. {
  73. n = read(), m = read();
  74. for (int i = 1; i <= n; i++) {
  75. seg[i].l = read();
  76. seg[i].r = read();
  77. seg[i].len = seg[i].r-seg[i].l;
  78. }
  79. sort(seg+1, seg+n+1);
  80. dx_init();
  81. build(root, 1, dx_top);
  82. int ans = INT_MAX;
  83. int l = 1, r = 0;
  84. while (r < n) {
  85. while (r < n && query(root, 1, dx_top) < m)
  86. ++r, modify(root, seg[r].l, seg[r].r, 1);
  87. if (query(root, 1, dx_top) >= m)
  88. ans = min(ans, seg[r].len-seg[l].len);
  89. while (l <= n && query(root, 1, dx_top) >= m) {
  90. if (query(root, 1, dx_top) >= m)
  91. ans = min(ans, seg[r].len-seg[l].len);
  92. modify(root, seg[l].l, seg[l].r, -1);
  93. l++;
  94. }
  95. if (query(root, 1, dx_top) >= m)
  96. ans = min(ans, seg[r].len-seg[l].len);
  97. }
  98. if (ans == INT_MAX)
  99. puts("-1");
  100. else printf("%d\n", ans);
  101. return 0;
  102. }

NOI2015 寿司餐厅

每个数大于的质因子最多只有一个,然后把相同的化为一类,大力分类讨论dp即可。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 505;
  4. int n;
  5. long long P;
  6. int prime[] = {2, 3, 5, 7, 11, 13, 17, 19};
  7. long long dp[2][1<<8|1][1<<8|1];
  8. long long p[2][2][1<<8|1][1<<8|1];
  9. vector<int> kind[MAXN];
  10. int main()
  11. {
  12. scanf("%d%lld", &n, &P);
  13. for (int i = 2; i <= n; i++) {
  14. int S = 0, num = i;
  15. for (int j = 0; j < 8; j++)
  16. if (num%prime[j] == 0) {
  17. S |= 1<<j;
  18. while (num%prime[j] == 0) num /= prime[j];
  19. }
  20. if (num == 1) kind[n+1].push_back(S);
  21. else kind[num].push_back(S);
  22. }
  23. int now = 0, nxt = 1;
  24. dp[now][0][0] = 1;
  25. for (register int i = 0; i <= n; i++) {
  26. int nw = 0, nx = 1;
  27. if (kind[i].empty()) continue;
  28. memcpy(p[0][nw], dp[now], sizeof dp[now]);
  29. memset(p[0][nx], 0, sizeof p[0][nx]);
  30. memcpy(p[1][nw], dp[now], sizeof dp[now]);
  31. memset(p[1][nx], 0, sizeof p[1][nx]);
  32. for (register vector<int>::iterator l = kind[i].begin(); l != kind[i].end(); ++l) {
  33. //cerr << i << " " << *l << endl;
  34. for (register int j = 0; j < 1<<8; j++)
  35. for (register int k = 0; k < 1<<8; k++) {
  36. (p[0][nx][j][k] += p[0][nw][j][k]) %= P;
  37. (p[1][nx][j][k] += p[1][nw][j][k]) %= P;
  38. (p[0][nx][j|(*l)][k] += p[0][nw][j][k]) %= P;
  39. (p[1][nx][j][k|(*l)] += p[1][nw][j][k]) %= P;
  40. }
  41. memset(p[0][nw], 0, sizeof p[0][nw]);
  42. memset(p[1][nw], 0, sizeof p[1][nw]);
  43. swap(nw, nx);
  44. }
  45. for (register int j = 0; j < 1<<8; j++)
  46. for (register int k = 0; k < 1<<8; k++)
  47. dp[now][j][k] = (p[0][nw][j][k]+p[1][nw][j][k]-dp[now][j][k])%P;
  48. }
  49. for (register int i = 1; i <= kind[n+1].size(); i++) {
  50. int S = kind[n+1][i-1];
  51. for (register int j = 0; j < 1<<8; j++)
  52. for (register int k = 0; k < 1<<8; k++) {
  53. long long val = dp[now][j][k];
  54. (dp[nxt][j][k] += val) %= P;
  55. (dp[nxt][j][k|S] += val) %= P;
  56. (dp[nxt][j|S][k] += val) %= P;
  57. }
  58. memset(dp[now], 0, sizeof dp[now]);
  59. swap(now, nxt);
  60. }
  61. long long ans = 0;
  62. for (register int j = 0; j < 1<<8; j++) {
  63. for (register int k = 0; k < 1<<8; k++) {
  64. if ((j&k) == 0)
  65. (ans += dp[now][j][k]) %= P;
  66. //cerr << dp[now][j][k] << " ";
  67. }
  68. //cerr << endl;
  69. }
  70. printf("%lld\n", (ans+P)%P);
  71. return 0;
  72. }

「NOI2015」荷马史诗

真...哈夫曼编码裸题

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 100050;
  4. long long w[MAXN];
  5. int n, k;
  6. long long tot_len = 0;
  7. struct pt {
  8. long long val;
  9. int lev;
  10. friend bool operator < (const pt &a, const pt &b)
  11. { return a.val == b.val ? a.lev > b.lev : a.val > b.val; }
  12. };
  13. priority_queue<pt> heap;
  14. int main()
  15. {
  16. scanf("%d%d", &n, &k);
  17. for (int i = 1; i <= n; i++) scanf("%lld", &w[i]);
  18. while ((n-1)%(k-1) != 0) w[++n] = 0;
  19. for (int i = 1; i <= n; i++) heap.push((pt){w[i], 0});
  20. while (heap.size() > 1) {
  21. long long val = 0;
  22. int lev = 0;
  23. for (int i = 1; i <= k; i++) {
  24. pt a = heap.top(); heap.pop();
  25. val += a.val, lev = max(lev, a.lev);
  26. }
  27. tot_len += val;
  28. heap.push((pt){val, lev+1});
  29. }
  30. cout << tot_len << endl << heap.top().lev << endl;
  31. return 0;
  32. }

4545: DQS的trie

LCT维护广义后缀自动机Right集合大小.......................
太TM难写了啊...
「不过貌似用splay维护dfs序要好写一点...什么时候尝试一个」

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 300005;
  4. struct link_cut_trees {
  5. int chl[MAXN][2], fa[MAXN], rev[MAXN];
  6. int tag[MAXN], dat[MAXN];
  7. int stk[MAXN], top;
  8. bool is_rt(int x)
  9. { return chl[fa[x]][0] != x && chl[fa[x]][1] != x;}
  10. inline void pdw(int nd)
  11. {
  12. if (chl[nd][0]) tag[chl[nd][0]] += tag[nd], rev[chl[nd][0]] ^= rev[nd];
  13. if (chl[nd][1]) tag[chl[nd][1]] += tag[nd], rev[chl[nd][1]] ^= rev[nd];
  14. if (rev[nd]) swap(chl[nd][0], chl[nd][1]);
  15. dat[nd] += tag[nd];
  16. rev[nd] = 0, tag[nd] = 0;
  17. }
  18. void zig(int nd)
  19. {
  20. int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p;
  21. int son = chl[nd][tp^1];
  22. if (son) fa[son] = p; if (!is_rt(p)) chl[g][tg] = nd;
  23. fa[nd] = g, fa[p] = nd, chl[nd][tp^1] = p, chl[p][tp] = son;
  24. }
  25. void splay(int nd)
  26. {
  27. stk[top = 1] = nd;
  28. for (int i = nd; !is_rt(i); i = fa[i]) stk[++top] = fa[i];
  29. while (top) pdw(stk[top--]);
  30. while (!is_rt(nd)) {
  31. int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p;
  32. if (is_rt(p)) { zig(nd); break; }
  33. if (tp == tg) zig(p), zig(nd);
  34. else zig(nd), zig(nd);
  35. }
  36. }
  37. void access(int x)
  38. {
  39. for (int y = 0; x; x = fa[y = x])
  40. splay(x), chl[x][1] = y;
  41. }
  42. void make_rt(int x)
  43. { access(x), splay(x), rev[x] ^= 1; }
  44. void link(int x, int y) // x --> y
  45. {
  46. fa[x] = y, access(y), splay(y), tag[y] += dat[x];
  47. }
  48. void cut(int x)
  49. {
  50. access(x), splay(x), tag[chl[x][0]] -= dat[x];
  51. fa[chl[x][0]] = 0, chl[x][0] = 0;
  52. }
  53. int get_dat(int x)
  54. {
  55. access(x), splay(x);
  56. return dat[x];
  57. }
  58. } ;
  59. struct SAM {
  60. int chl[MAXN][3], fa[MAXN], maxl[MAXN], top, root;
  61. link_cut_trees LCT;
  62. long long ans;
  63. SAM()
  64. { top = root = 1, ans = 0; }
  65. int push(int nd, int x)
  66. {
  67. int p = nd, np = ++top; LCT.dat[np] = 1, maxl[np] = maxl[p]+1;
  68. while (p && !chl[p][x]) chl[p][x] = np, p = fa[p];
  69. if (!p) fa[np] = root, ans += maxl[np]-maxl[fa[np]], LCT.link(np, root);
  70. else {
  71. int q = chl[p][x];
  72. if (maxl[q] == maxl[p]+1) fa[np] = q, ans += maxl[np]-maxl[fa[np]], LCT.link(np, q);
  73. else {
  74. int nq = ++top; maxl[nq] = maxl[p]+1;
  75. memcpy(chl[nq], chl[q], sizeof chl[q]);
  76. fa[nq] = fa[q], LCT.link(nq, fa[nq]);
  77. ans += maxl[nq]-maxl[fa[nq]];
  78. ans -= maxl[q]-maxl[fa[q]];
  79. fa[q] = fa[np] = nq;
  80. ans += maxl[q]-maxl[fa[q]], ans += maxl[np]-maxl[fa[np]];
  81. LCT.cut(q), LCT.cut(np), LCT.link(np, nq), LCT.link(q, nq);
  82. while (p && chl[p][x] == q) chl[p][x] = nq, p = fa[p];
  83. }
  84. }
  85. return np;
  86. }
  87. int get_pt(int nd, const char *str)
  88. {
  89. if (*str == '\0') return nd;
  90. if (!chl[nd][*str-'a']) return -1;
  91. return get_pt(chl[nd][*str-'a'], str+1);
  92. }
  93. inline long long diff_substring()
  94. { return ans; }
  95. inline int match_times(const char *str)
  96. {
  97. int nd = get_pt(root, str);
  98. if (nd == -1) return 0;
  99. return LCT.get_dat(nd);
  100. }
  101. };
  102. struct trie {
  103. struct node {
  104. int to, next;
  105. char dis;
  106. } edge[MAXN*2];
  107. int head[MAXN], top;
  108. inline void push(int i, int j, char c)
  109. { edge[++top] = (node){j, head[i], c}, head[i] = top; }
  110. int stat[MAXN], vis[MAXN];
  111. int root;
  112. SAM autometa;
  113. queue<int> que;
  114. trie()
  115. { root = 1, stat[root] = 1, top = 0; }
  116. void dfs(int x)
  117. {
  118. vis[x] = 1;
  119. for (int i = head[x]; i; i = edge[i].next) {
  120. int to = edge[i].to, c = edge[i].dis-'a';
  121. if (vis[to]) continue;
  122. stat[to] = autometa.push(stat[x], c);
  123. dfs(to);
  124. }
  125. }
  126. inline int match_times(const char *str)
  127. { return autometa.match_times(str); }
  128. inline long long diff_substring()
  129. { return autometa.diff_substring(); }
  130. } T;
  131. int n, m;
  132. int id;
  133. char str[MAXN];
  134. int main()
  135. {
  136. scanf("%d%d", &id, &n);
  137. for (int i = 1; i < n; i++) {
  138. int u, v; char c;
  139. scanf("%d%d %c\n", &u, &v, &c);
  140. T.push(u, v, c), T.push(v, u, c);
  141. }
  142. T.dfs(1);
  143. scanf("%d", &m);
  144. for (int i = 1; i <= m; i++) {
  145. int opt, r, t;
  146. scanf("%d", &opt);
  147. if (opt == 1) {
  148. printf("%lld\n", T.diff_substring());
  149. } else if (opt == 2) {
  150. scanf("%d%d", &r, &t), t--;
  151. while (t--) {
  152. int u, v;
  153. char c;
  154. scanf("%d%d %c\n", &u, &v, &c);
  155. T.push(u, v, c), T.push(v, u, c);
  156. }
  157. T.dfs(r);
  158. } else if (opt == 3) {
  159. scanf("%s", str);
  160. printf("%d\n", T.match_times(str));
  161. } else throw;
  162. }
  163. return 0;
  164. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注