[关闭]
@2368860385 2018-12-20T11:19:06.000000Z 字数 6101 阅读 206

北京八十中集训——day4

比赛总结


预计:100+100+0
实际:100+100+0
第三题最后1分钟交的,一交就测了(按提交时间逆序评测),不用预计了,直接返回了成绩。

考试过程

T1
感觉比较可做,写了三个小时,有点慢了,最后由于一个bug调了很长时间,和暴力拍上就交了(一直担心暴力也是错的。。)
T2
读完题感觉是树形背包,写完T1,写了半小时,过了样例,就交了。试了几组小样例,发现了一个bug!!!,然后改,改完过了就交了;又试了一组小样例,又发现一个bug,改过又交了;又试了一组小样例,又发现一个bug,改过又叫了....(重复几次);由于不知道怎么拍,只能靠造几组小样例检验,最后又改了几个地方,使代码更安全,就交了。

幸亏多试了几组,前面的交的全0分。。
T3
写完前两道,看的第三道,(T1花了3个小时,T2半小时,此时还有半小时),读完好像是网络流,感觉不能这么简单吧。。仔细想了会,好像就是网络流。好像有点不敢写(想到noip day1 T3),不过这次还好,坚信,就是简单题!
于是就写了,不过时间紧,思绪混乱,没调出。
混乱到什么程度?开始想二分最大值,写着写着忘了。用费用流判断是否满流。。

总结:
时间分配,T1花的时间有点长。
T3比较好,这次敢写了,其实就是网络流。

T1

n^3:枚举一条水平线,枚举一个高度,计算以这个高度,底是这条线的矩形的贡献。居然可以有70分。
n^2:枚举一条水平线,计算所有以这条水平线为底的矩形的贡献。

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<cmath>
  6. #include<cctype>
  7. #include<set>
  8. #include<map>
  9. #include<queue>
  10. #include<vector>
  11. using namespace std;
  12. typedef long long LL;
  13. inline int read() {
  14. int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
  15. for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
  16. }
  17. const int N = 2005;
  18. LL tot[N][N], sum2[N], h[N][N], sumh[N][N];
  19. char s[N][N];
  20. inline LL Calc(LL m) { // xigema i=0 to m i * (n - i + 1)
  21. return m * (m + 1) / 2 * m - sum2[m] + (m * (m + 1)) / 2;
  22. }
  23. void init(int n,int m) {
  24. int mx = max(n, m);
  25. for (int i = 1; i <= mx; ++i) sum2[i] = sum2[i - 1] + i * i;
  26. for (int i = 1; i <= n; ++i)
  27. for (int j = 1; j <= m; ++j)
  28. tot[i][j] = Calc(i) * Calc(j), h[i][j] = Calc(j) * i;
  29. for (int j = 1; j <= m; ++j)
  30. for (int i = 1; i <= n; ++i)
  31. sumh[i][j] += sumh[i - 1][j] + h[i][j];
  32. }
  33. /*
  34. namespace BF1{
  35. int sum[N][N];
  36. // int tmp[N];
  37. void solve2(int n,int m) {
  38. LL Ans = 0;
  39. for (int i = 1; i <= n; ++i)
  40. for (int j = 1; j <= m; ++j)
  41. sum[i][j] = sum[i - 1][j] + (s[i][j] == '#');
  42. for (int i = 1; i <= n; ++i) {
  43. for (int j = i; j <= n; ++j) {
  44. int last = 0;
  45. for (int k = 1; k <= m; ++k)
  46. if (sum[j][k] - sum[i - 1][k])
  47. // Ans += h[j - i + 1][k - 1 - last], last = k;
  48. // tmp[j] += 1ll * Calc(k - 1 - last) * (j - i + 1),
  49. Ans += 1ll * Calc(k - 1 - last) * (j - i + 1), last = k;
  50. // if (last != m) Ans += h[j - i + 1][m - last];
  51. if (last != m) Ans += 1ll * Calc(m - last) * (j - i + 1);
  52. // tmp[j] += 1ll * Calc(m - last) * (j - i + 1);
  53. }
  54. }
  55. // for (int i = 1; i <= n; ++i) cout << tmp[i] << " "; puts("");
  56. cout << Ans;
  57. }
  58. }
  59. */
  60. int sk[N], u[N][N];
  61. inline LL Calc2(int i,int j,int x,int y) {
  62. if (x == y) return 0;
  63. return sumh[y][j - i] - sumh[x][j - i];
  64. }
  65. void solve(int n,int m) {
  66. for (int i = 1; i <= n; ++i)
  67. for (int j = 1; j <= m; ++j)
  68. u[i][j] = (s[i][j] == '.' ? u[i - 1][j] + 1 : 0);
  69. LL Ans = 0;
  70. for (int top, i = 1; i <= n; ++i) {
  71. // LL tmp = 0;
  72. top = 0; sk[++top] = 0;
  73. for (int j = 1; j <= m; ++j) {
  74. while (top && u[i][j] < u[i][sk[top]]) {
  75. Ans += Calc2(sk[top - 1], j - 1, max(u[i][j], u[i][sk[top - 1]]), u[i][sk[top]]);
  76. // tmp += Calc2(sk[top - 1], j - 1, max(u[i][j], u[i][sk[top - 1]]), u[i][sk[top]]);
  77. top --;
  78. }
  79. while (top && u[i][j] == u[i][sk[top]]) top--;
  80. sk[++top] = j;
  81. }
  82. while (top >= 2) {
  83. // tmp += Calc2(sk[top - 1], m, u[i][sk[top - 1]], u[i][sk[top]]);
  84. Ans += Calc2(sk[top - 1], m, u[i][sk[top - 1]], u[i][sk[top]]); top --;
  85. // Ans += Calc2(sk[top - 1], sk[top], u[i][sk[top - 1]], u[i][sk[top]]);top --;
  86. }
  87. // cout << tmp << " ";
  88. }
  89. // puts("");
  90. cout << Ans;
  91. }
  92. int main() {
  93. // freopen("1.txt", "r", stdin);
  94. int n = read(), m = read();
  95. for (int i = 1; i <= n; ++i) scanf("%s", s[i] + 1);
  96. init(n, m);
  97. // if (n <= 300 && m <= 300) { BF1::solve2(n, m); return 0; }
  98. solve(n, m);
  99. return 0;
  100. }
  101. /*
  102. 4 5
  103. #.##.
  104. .#...
  105. #.#..
  106. ..#..
  107. 5 6
  108. ..#..#
  109. #.####
  110. #.#.##
  111. .##..#
  112. ##.###
  113. */

T2

树形dp,有一种情况是进去又不回来了,还有进去后回来。分别转移。

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<cmath>
  6. #include<cctype>
  7. #include<set>
  8. #include<map>
  9. #include<queue>
  10. #include<vector>
  11. using namespace std;
  12. typedef long long LL;
  13. inline int read() {
  14. int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
  15. for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
  16. }
  17. const int N = 505;
  18. int f[N][N][2], w[N], siz[N];
  19. vector<int> T[N];
  20. int n, m;
  21. void dfs(int u,int fa) {
  22. f[u][1][0] = f[u][1][1] = w[u]; siz[u] = 1;
  23. for (int sz = T[u].size(), i = 0; i < sz; ++i) {
  24. int v = T[u][i];
  25. if (v == fa) continue;
  26. dfs(v, u);
  27. siz[u] += siz[v];
  28. for (int j = min(siz[u] * 3, m); j >= 1; --j) {
  29. for (int k = 0, lim = min(j, min(siz[v] * 3, m)); k <= lim; ++k) {
  30. if (j - k - 1 >= 0) f[u][j][0] = max(f[u][j][0], f[v][k][0] + f[u][j - k - 1][1]);
  31. if (j - k - 2 >= 0) f[u][j][0] = max(f[u][j][0], f[v][k][1] + f[u][j - k - 2][0]);
  32. if (j - k - 2 >= 0) f[u][j][1] = max(f[u][j][1], f[v][k][1] + f[u][j - k - 2][1]);
  33. }
  34. }
  35. }
  36. }
  37. int main() {
  38. // freopen("1.txt", "r", stdin);
  39. n = read(), m = read();
  40. for (int i = 1; i <= n; ++i) w[i] = read();
  41. for (int i = 1; i < n; ++i) {
  42. int u =read(),v = read(); T[u].push_back(v); T[v].push_back(u);
  43. }
  44. dfs(1, 0);
  45. int ans = 0;
  46. for (int i = 0; i <= m; ++i) ans = max(ans, max(f[1][i][0], f[1][i][1]));
  47. cout << ans;
  48. return 0;
  49. }
  50. /*
  51. 2 1
  52. 8 9
  53. 1 2
  54. 2 2
  55. 8 9
  56. 1 2
  57. 2 3
  58. 8 9
  59. 1 2
  60. 3 5
  61. 9 2 5
  62. 1 2
  63. 1 3
  64. 5 8
  65. 3 2 3 4 1
  66. 1 2
  67. 1 3
  68. 2 4
  69. 2 5
  70. */

T3

二分最大值,建图,网络流判断是否满流。

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<cmath>
  6. #include<cctype>
  7. #include<set>
  8. #include<map>
  9. #include<queue>
  10. #include<vector>
  11. using namespace std;
  12. typedef long long LL;
  13. inline int read() {
  14. int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
  15. for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
  16. }
  17. const int N = 105 * 5;
  18. struct Edge{
  19. int to, nxt, c;
  20. Edge() {}
  21. Edge(int x,int y,int z) { to = x, nxt = y, c = z; }
  22. }e[1000005];
  23. struct Node{
  24. int x, y;
  25. }A[N], B[N];
  26. int head[N], q[N], dis[N], D[N][N], cur[N];
  27. vector<int> C[N];
  28. int En = 1, S, T, n, m, c, k;
  29. inline void add_edge(int u,int v,int w) {
  30. ++En; e[En] = Edge(v, head[u], w); head[u] = En;
  31. ++En; e[En] = Edge(u, head[v], 0); head[v] = En;
  32. }
  33. inline int sqr(int x) { return x * x; }
  34. inline int dist(const Node &A,const Node &B) { return sqr(A.x - B.x) + sqr(A.y - B.y); }
  35. bool bfs() {
  36. for (int i = 0; i <= T; ++i) dis[i] = -1, cur[i] = head[i];
  37. int L = 1, R = 0; q[++R] = S, dis[S] = 0;
  38. while (L <= R) {
  39. int u = q[L ++];
  40. for (int i = head[u]; i; i = e[i].nxt) {
  41. int v = e[i].to;
  42. if (dis[v] == -1 && e[i].c > 0) {
  43. dis[v] = dis[u] + 1; q[++R] = v;
  44. if (v == T) return 1;
  45. }
  46. }
  47. }
  48. return 0;
  49. }
  50. int dfs(int u,int flow) {
  51. if (u == T) return flow;
  52. int used = 0;
  53. for (int &i = cur[u]; i; i = e[i].nxt) {
  54. int v = e[i].to;
  55. if (dis[v] == dis[u] + 1 && e[i].c > 0) {
  56. int t = dfs(v, min(flow - used, e[i].c));
  57. if (t > 0) {
  58. e[i].c -= t, e[i ^ 1].c += t;
  59. used += t;
  60. if (used == flow) break;
  61. }
  62. }
  63. }
  64. if (flow != used) dis[u] = -1;
  65. return used;
  66. }
  67. int Dinic() {
  68. int ans = 0;
  69. while (bfs()) ans += dfs(S, 1e9);
  70. return ans;
  71. }
  72. bool check(int x) {
  73. En = 1;
  74. for (int i = 0; i <= T; ++i) head[i] = 0; // T!!! not n
  75. for (int i = 1; i <= n; ++i) add_edge(S, i, 1);
  76. for (int i = 1; i<= n; ++i)
  77. for (int j = 1; j <= m; ++j)
  78. if (D[i][j] <= x) add_edge(i, j + n, 1);
  79. for (int i = 1; i <=k; ++i)
  80. for (int sz = C[i].size(), j = 0; j < sz; ++j)
  81. add_edge(C[i][j] + n, i + n + m, 1e9);
  82. for (int i = 1; i <= k; ++i) add_edge(i + n + m, T, c);
  83. return Dinic() == n;
  84. }
  85. int main() {
  86. n = read(), m =read(), c = read(), k = read();
  87. for (int i = 1; i <= n; ++i) A[i].x = read(), A[i].y = read();
  88. for (int i = 1; i <= m; ++i) B[i].x = read(), B[i].y = read();
  89. for (int i = 1; i <= k; ++i)
  90. for (int T = read(); T--; ) C[i].push_back(read());
  91. S = 0, T = n + m + k + 1; // T = n + n + k !!!
  92. int L = 0, R = 0, ans = 0;
  93. for (int i = 1; i <= n; ++i)
  94. for (int j = 1; j <= m; ++j)
  95. R = max(R, D[i][j] = dist(A[i], B[j]));
  96. while (L <= R) {
  97. int mid = (L + R) >> 1;
  98. if (check(mid)) ans = mid, R = mid - 1;
  99. else L = mid + 1;
  100. }
  101. cout << ans;
  102. return 0;
  103. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注