[关闭]
@ljt12138 2017-06-19T21:33:30.000000Z 字数 9549 阅读 757

湖师大集训记录

lyoi303:「2017 山东一轮集训 Day1」Sum

吕老板讲的方法只有50....

TLE

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int p, n, m;
  4. const int mod = 998244353, g = 3;
  5. int power(int a, int n)
  6. {
  7. int ans = 1, b = a;
  8. for (register int i = 0; i <= 30; i++) {
  9. if ((n>>i)&1) ans = (long long)ans*b%mod;
  10. b = (long long)b*b%mod;
  11. }
  12. return ans;
  13. }
  14. inline int inv(int a)
  15. { return power(a, mod-2); }
  16. const int MAXN = 2049;
  17. int rev[MAXN];
  18. void NTT(int a[], int n, int flag)
  19. {
  20. int m = 1, lgn = 0;
  21. while (m < n) lgn++, m <<= 1;
  22. rev[0] = 0;
  23. for (register int i = 1; i < n; i++) rev[i] = (rev[i>>1]>>1)|((i&1)<<(lgn-1));
  24. for (register int i = 0; i < n; i++)
  25. if (rev[i] < i) swap(a[i], a[rev[i]]);
  26. for (register int k = 1; k <= n; k <<= 1) {
  27. int dw = power(g, (mod-1)/k);
  28. if (flag == -1) dw = inv(dw);
  29. for (register int i = 0; i < n; i += k) {
  30. int w = 1;
  31. for (register int j = 0; j < k>>1; j++) {
  32. int u = a[i+j], t = (long long)w*a[i+j+(k>>1)]%mod;
  33. a[i+j] = (u+t)%mod, a[i+j+(k>>1)] = ((u-t)%mod+mod)%mod;
  34. w = (long long)w*dw%mod;
  35. }
  36. }
  37. }
  38. if (flag == -1) {
  39. int Inv = inv(n);
  40. for (register int i = 0; i < n; i++)
  41. a[i] = (long long)Inv*a[i]%mod;
  42. }
  43. }
  44. int B[2049], C[2049];
  45. void mul(int a[2049], int M, int b[2049], int c[2049]) // $a = b\oplus c$
  46. {
  47. memcpy(B, b, sizeof B), memcpy(C, c, sizeof C);
  48. memset(a, 0, sizeof B);
  49. int n = 1;
  50. while (n < M) n <<= 1;
  51. n <<= 1; // todo here
  52. NTT(B, n, 1), NTT(C, n, 1);
  53. for (register int i = 0; i < n; i++)
  54. a[i] = (long long)B[i]*C[i]%mod;
  55. NTT(a, n, -1);
  56. for (register int i = M; i < 2048; i++)
  57. a[i] = 0;
  58. }
  59. struct node {
  60. int N, Pow; // 10^N = Pow;
  61. int A[55][2049];
  62. void print()
  63. {
  64. puts("Matrix : ");
  65. for (int i = 0; i < p; i++) {
  66. for (int j = 0; j <= m; j++)
  67. cerr << A[i][j] << " ";
  68. cerr << endl;
  69. }
  70. puts("End Matrix.");
  71. }
  72. node() {
  73. memset(A, 0, sizeof A);
  74. }
  75. friend node operator * (node &a, node &b)
  76. {
  77. node ret;
  78. static int A[MAXN];
  79. memset(A, 0, sizeof A);
  80. ret.N = a.N+b.N, ret.Pow = (long long)a.Pow*b.Pow%p;
  81. for (register int i = 0; i < p; i++) {
  82. for (register int j = 0; j < p; j++) {
  83. int M = ((long long)i*b.Pow%p+j)%p;
  84. mul(A, m+1, a.A[i], b.A[j]);
  85. for (register int k = 0; k <= m; k++) (ret.A[M][k] += A[k]) %= mod;
  86. }
  87. }
  88. return ret;
  89. }
  90. };
  91. node power(node a, int n)
  92. {
  93. node ans;
  94. int flag = -1;
  95. for (int i = 0; i <= 30; i++) {
  96. if ((n>>i) == 0) break;
  97. if ((n>>i)&1) {
  98. if (flag == -1) ans = a, flag = 1;
  99. else ans = ans*a;
  100. }
  101. a = a*a;
  102. }
  103. return ans;
  104. }
  105. node A;
  106. int a[MAXN], b[MAXN], c[MAXN];
  107. int main()
  108. {
  109. scanf("%d%d%d", &n, &p, &m);
  110. A.N = 1, A.Pow = 10;
  111. for (int j = 0; j <= min(m, 9); j++)
  112. A.A[j%p][j]++;
  113. A = power(A, n);
  114. int ans = 0;
  115. for (int i = 0; i <= m; i++) {
  116. ans = (ans+A.A[0][i])%mod;
  117. printf("%d ", ans);
  118. }
  119. puts("");
  120. return 0;
  121. }

upd: 原来是我走神了QwQ。
做循环卷积的时候要先全部DFT,卷完了全部IDFT,复杂度少一个...
AC...

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int p, n, m;
  4. const int mod = 998244353, g = 3;
  5. int power(int a, int n)
  6. {
  7. int ans = 1, b = a;
  8. for (register int i = 0; i <= 30; i++) {
  9. if ((n>>i)&1) ans = (long long)ans*b%mod;
  10. b = (long long)b*b%mod;
  11. }
  12. return ans;
  13. }
  14. inline int inv(int a)
  15. { return power(a, mod-2); }
  16. const int MAXN = 2049;
  17. int rev[MAXN];
  18. void NTT(int a[], int n, int flag)
  19. {
  20. int m = 1, lgn = 0;
  21. while (m < n) lgn++, m <<= 1;
  22. rev[0] = 0;
  23. for (register int i = 1; i < n; i++) rev[i] = (rev[i>>1]>>1)|((i&1)<<(lgn-1));
  24. for (register int i = 0; i < n; i++)
  25. if (rev[i] < i) swap(a[i], a[rev[i]]);
  26. for (register int k = 1; k <= n; k <<= 1) {
  27. int dw = power(g, (mod-1)/k);
  28. if (flag == -1) dw = inv(dw);
  29. for (register int i = 0; i < n; i += k) {
  30. int w = 1;
  31. for (register int j = 0; j < k>>1; j++) {
  32. int u = a[i+j], t = (long long)w*a[i+j+(k>>1)]%mod;
  33. a[i+j] = (u+t)%mod, a[i+j+(k>>1)] = ((u-t)%mod+mod)%mod;
  34. w = (long long)w*dw%mod;
  35. }
  36. }
  37. }
  38. if (flag == -1) {
  39. int Inv = inv(n);
  40. for (register int i = 0; i < n; i++)
  41. a[i] = (long long)Inv*a[i]%mod;
  42. }
  43. }
  44. int B[2049], C[2049];
  45. void mul(int a[2049], int M, int b[2049], int c[2049]) // $a = b\oplus c$
  46. {
  47. memcpy(B, b, sizeof B), memcpy(C, c, sizeof C);
  48. memset(a, 0, sizeof B);
  49. int n = 1;
  50. while (n < M) n <<= 1;
  51. n <<= 1; // todo here
  52. cerr << n << endl;
  53. NTT(B, n, 1), NTT(C, n, 1);
  54. for (register int i = 0; i < n; i++)
  55. a[i] = (long long)B[i]*C[i]%mod;
  56. NTT(a, n, -1);
  57. for (register int i = M; i < 2048; i++)
  58. a[i] = 0;
  59. }
  60. struct node {
  61. int N, Pow; // 10^N = Pow;
  62. int A[55][2049];
  63. void display()
  64. {
  65. puts("Matrix : ");
  66. for (int i = 0; i < p; i++) {
  67. for (int j = 0; j <= m; j++)
  68. cerr << A[i][j] << " ";
  69. cerr << endl;
  70. }
  71. puts("End Matrix.");
  72. }
  73. node() {
  74. memset(A, 0, sizeof A);
  75. }
  76. friend node operator * (node a, node b)
  77. {
  78. node ret;
  79. static int C[55][MAXN], d[MAXN];
  80. memset(C, 0, sizeof C);
  81. ret.N = a.N+b.N, ret.Pow = (long long)a.Pow*b.Pow%p;
  82. int np = 1;
  83. while (np < m+1) np <<= 1;
  84. np <<= 1; // todo here
  85. for (int i = 0; i < p; i++) NTT(a.A[i], np, 1), NTT(b.A[i], np, 1);
  86. for (int i = 0; i < p; i++) {
  87. for (int j = 0; j < p; j++) {
  88. int M = ((long long)i*b.Pow%p+j)%p;
  89. for (int k = 0; k < np; k++)
  90. C[M][k] = (C[M][k]+(long long)a.A[i][k]*b.A[j][k]%mod)%mod;
  91. }
  92. }
  93. for (int i = 0; i < p; i++) {
  94. NTT(a.A[i], np, -1), NTT(b.A[i], np, -1),
  95. NTT(C[i], np, -1);
  96. for (int k = 0; k <= m; k++) ret.A[i][k] = (ret.A[i][k]+C[i][k])%mod;
  97. }
  98. return ret;
  99. }
  100. };
  101. node power(node a, int n)
  102. {
  103. node ans;
  104. int flag = -1;
  105. for (int i = 0; i <= 30; i++) {
  106. if ((n>>i) == 0) break;
  107. if ((n>>i)&1) {
  108. if (flag == -1) ans = a, flag = 1;
  109. else ans = ans*a;
  110. }
  111. a = a*a;
  112. }
  113. return ans;
  114. }
  115. node A;
  116. int a[MAXN], b[MAXN], c[MAXN];
  117. int main()
  118. {
  119. scanf("%d%d%d", &n, &p, &m);
  120. A.N = 1, A.Pow = 10;
  121. for (int j = 0; j <= min(m, 9); j++)
  122. A.A[j%p][j]++;
  123. A = power(A, n);
  124. int ans = 0;
  125. for (int i = 0; i <= m; i++) {
  126. ans = (ans+A.A[0][i])%mod;
  127. printf("%d ", ans);
  128. }
  129. puts("");
  130. return 0;
  131. }

lyoi306「2017 山东一轮集训 Day2」Pair

考虑匹配条件,令也就是。显然,一个序列匹配当且仅当排序后匹配。考虑排序后的情况,容易发现,匹配当且仅当(排序后)对于任何一个前缀,的数量不少于。如果把看成左括号,看成右括号,就是经典的括号序列匹配问题了。用线段树维护前缀和的区间最小值即可。

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

lyoi323. 「2017 山东一轮集训 Day7」养猫

神奇的费用流...最大流限制/费用计算的好模型。

from visit_world
把 1 到 n 串成一条链
考虑上限:
想象你带了 mx 个小弟在链上走,到一个位置 p,你可以派出一个小弟去获得对应收益,但是他在 p + k 的时候才能归队
考虑下限:
在 p 这里派出一个小弟,会使得 [p, p+k) 上走“主干道”的小弟减少一名。
因此,我们限制“主干道”的流量为 mx - mi 即可满足下限

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int MAXN = 1005;
  4. int n, k, ms, me;
  5. int mx, mn;
  6. int s[MAXN], e[MAXN];
  7. struct node {
  8. int to, next, flow;
  9. long long cost;
  10. int neg;
  11. } edge[MAXN*200];
  12. int head[MAXN], top = 0;
  13. inline int push(int i, int j, int f, long long c)
  14. {
  15. ++top, edge[top] = (node) {j, head[i], f, c, top+1}, head[i] = top;
  16. ++top, edge[top] = (node) {i, head[j], 0, -c, top-1}, head[j] = top;
  17. return top-1;
  18. }
  19. long long dis[MAXN];
  20. int vis[MAXN];
  21. queue<int> que;
  22. int pre[MAXN], pre_edge[MAXN];
  23. int S = MAXN-1, T = MAXN-2;
  24. const long long inf = 1e14;
  25. bool spfa(int &flow, long long &cost)
  26. {
  27. memset(vis, 0, sizeof vis), memset(dis, 127/3, sizeof dis);
  28. vis[S] = 1, dis[S] = 0, que.push(S);
  29. while (!que.empty()) {
  30. int nd = que.front(); que.pop(), vis[nd] = 0;
  31. for (int i = head[nd]; i; i = edge[i].next) {
  32. int to = edge[i].to;
  33. if (!edge[i].flow || dis[to] <= dis[nd]+edge[i].cost) continue;
  34. dis[to] = dis[nd]+edge[i].cost, pre[to] = nd, pre_edge[to] = i;
  35. if (!vis[to])
  36. vis[to] = 1, que.push(to);
  37. }
  38. }
  39. if (dis[T] > inf) return 0;;
  40. int mf = INT_MAX;
  41. for (int i = T; i != S; i = pre[i]) mf = min(mf, edge[pre_edge[i]].flow);
  42. for (int i = T; i != S; i = pre[i])
  43. edge[pre_edge[i]].flow -= mf, edge[edge[pre_edge[i]].neg].flow += mf;
  44. cost += dis[T]*mf;
  45. flow += mf;
  46. return 1;
  47. }
  48. void mcf(int &flow, long long &cost)
  49. {
  50. cost = flow = 0;
  51. while (spfa(flow, cost));
  52. }
  53. int eg[MAXN];
  54. int main()
  55. {
  56. scanf("%d%d%d%d", &n, &k, &ms, &me); // change t, t \le me, k-t \le ms \rightarrow t \ge k-ms
  57. mx = k-ms, mn = me; // [mn, mx]
  58. long long cnt = 0;
  59. for (int i = 1; i <= n; i++) scanf("%d", &s[i]), cnt += s[i]; // sleep
  60. for (int i = 1; i <= n; i++) scanf("%d", &e[i]);
  61. push(S, 1, mx, 0), push(n, T, mx, 0);
  62. for (int i = 1; i < n; i++) {
  63. if (i >= k) push(i, i+1, mx-mn, 0);
  64. else push(i, i+1, mx, 0);
  65. }
  66. for (int i = 1; i <= n; i++) {
  67. int t = i+k <= n?i+k:T;
  68. eg[i] = push(i, t, 1, -e[i]+s[i]);
  69. }
  70. int flow;
  71. long long cost;
  72. mcf(flow, cost);
  73. printf("%lld\n", cnt-cost);
  74. for (int i = 1; i <= n; i++) {
  75. if (edge[eg[i]].flow)
  76. putchar('S');
  77. else putchar('E');
  78. }
  79. puts("");
  80. return 0;
  81. }

loj#6060. 「2017 山东一轮集训 Day1」Set

首先有为定值,设为。考虑的每一位,如果为1,由于必然一边为1一边为0,对和的贡献不变;如果为0,则应该尽可能让更高位两边全为1。

做法1:首先取出为0的位做一遍最大异或找到中必须为1的位置,然后作出线性基。贪心的从高到低放置每一位,用异或方程组判断下面是否有解「太麻烦了根本写不出来...」
// 但这个思路扩展性更好,可以出道题233

做法2:考虑统一处理,在贪心求最大异或的时候改变贪心顺序,首先是为0的位,然后是为1的。直接做就好了。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. struct linear_base {
  4. long long A[70];
  5. void push(long long x, long long lim)
  6. {
  7. for (int i = 60; i >= 0; i--) {
  8. if (lim&(1ll<<i)) continue;
  9. if (!(x&(1ll<<i))) continue;
  10. if (!A[i]) { A[i] = x; return;}
  11. else x ^= A[i];
  12. }
  13. for (int i = 60; i >= 0; i--) {
  14. if (!(lim&(1ll<<i))) continue;
  15. if (!(x&(1ll<<i))) continue;
  16. if (!A[i]) { A[i] = x; return; }
  17. else x ^= A[i];
  18. }
  19. }
  20. long long max_xor(long long lim)
  21. {
  22. long long val = 0;
  23. for (int i = 60; i >= 0; i--)
  24. if (!(lim&(1ll<<i)) && !(val&(1ll<<i)))
  25. val ^= A[i];
  26. for (int i = 60; i >= 0; i--)
  27. if ((lim&(1ll<<i)) && !(val&(1ll<<i)))
  28. val ^= A[i];
  29. return val;
  30. }
  31. } lb;
  32. int n;
  33. long long val[100005], xr = 0;
  34. int main()
  35. {
  36. scanf("%d", &n);
  37. for (int i = 1; i <= n; i++) scanf("%lld", &val[i]), xr ^= val[i];
  38. for (int i = 1; i <= n; i++)
  39. lb.push(val[i], xr);
  40. printf("%lld\n", xr^lb.max_xor(xr));
  41. return 0;
  42. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注