[关闭]
@sensitive-cs 2017-06-18T15:44:43.000000Z 字数 3582 阅读 658

CF 419 div2

题解


B. Karen and Coffee
题意:
给出n个区间,对区间内的每一个数更新1次,给出一个整数k,然后给出q个区间,查询在每个区间内,有多少个数的更新次数是大于k的。
思路:
乍一看,以为是线段树模板,但是,不是这样的,但是这题是自己思考并且码出来了Orz。
首先,我们先写一个模板线段树,这样就可以查询到每个数被更新的次数,复杂度为nlgn,这个只用执行一次,然后再建立另外一颗线段树,用于查询大于等于k的个数就可以了,358ms,还是比较快的。
代码:

  1. #include <string.h>
  2. #include <stdio.h>
  3. int a[200005];
  4. int add[200005 << 2];
  5. int sum[200005 << 2];
  6. int num[200005 << 2];
  7. const int u = 200000;
  8. int n,k,q;
  9. int ans = 0;
  10. void pushup2(int rt)
  11. {
  12. num[rt] = num[rt << 1] + num[rt << 1|1];
  13. }
  14. void build2(int l,int r,int rt)
  15. {
  16. if (l == r)
  17. {
  18. if (a[l] >= k) num[rt] = 1;
  19. else num[rt] = 0;
  20. return;
  21. }
  22. int mid = (l + r) >> 1;
  23. build2(l,mid,rt << 1);
  24. build2(mid+1,r,rt << 1|1);
  25. pushup2(rt);
  26. }
  27. void query2(int ll,int rr,int l,int r,int rt)
  28. {
  29. if (ll <= l && r <= rr)
  30. {
  31. ans += num[rt];
  32. return;
  33. }
  34. int mid = (l + r) >> 1;
  35. if (ll <= mid) query2(ll,rr,l,mid,rt << 1);
  36. if (rr > mid) query2(ll,rr,mid+1,r,rt << 1|1);
  37. }
  38. void pushup(int rt)
  39. {
  40. sum[rt] = sum[rt << 1] + sum[rt << 1|1];
  41. }
  42. void build(int l,int r,int rt)
  43. {
  44. if (l == r)
  45. {
  46. sum[rt] = 0;
  47. return;
  48. }
  49. int m = (l+r) >> 1;
  50. build(l,m,rt << 1);
  51. build(m+1,r,rt << 1|1);
  52. pushup(rt);
  53. }
  54. void pushdown(int rt,int ln,int rn)
  55. {
  56. if (add[rt])
  57. {
  58. add[rt << 1] += add[rt];
  59. add[rt << 1|1] += add[rt];
  60. sum[rt << 1] += ln * add[rt];
  61. sum[rt << 1|1] += rn *add[rt];
  62. add[rt] = 0;
  63. }
  64. }
  65. void update(int ll,int rr,int c,int l,int r,int rt)
  66. {
  67. if (ll <= l && r <= rr)
  68. {
  69. sum[rt] += c*(r-l+1);
  70. add[rt] += c;
  71. return;
  72. }
  73. int m = (l+r) >> 1;
  74. pushdown(rt,m-l+1,r-m);
  75. if (ll <= m) update(ll,rr,c,l,m,rt << 1);
  76. if (rr > m) update(ll,rr,c,m+1,r,rt << 1|1);
  77. pushup(rt);
  78. }
  79. int query(int ll,int rr,int l,int r,int rt)
  80. {
  81. if (ll <= l && r <= rr)
  82. {
  83. return sum[rt];
  84. }
  85. int m = (l+r) >> 1;
  86. pushdown(rt,m-l+1,r-m);
  87. int ans = 0;
  88. if (ll <= m) ans += query(ll,rr,l,m,rt << 1);
  89. if (rr > m) ans += query(ll,rr,m+1,r,rt << 1|1);
  90. return ans;
  91. }
  92. int main()
  93. {
  94. scanf("%d%d%d",&n,&k,&q);
  95. build(1,u,1);
  96. for (int i = 0;i < n;i++)
  97. {
  98. int a,b;
  99. scanf("%d%d",&a,&b);
  100. update(a,b,1,1,u,1);
  101. }
  102. for (int i = 1;i <= u;i++)
  103. {
  104. a[i] = query(i,i,1,u,1);
  105. }
  106. build2(1,u,1);
  107. for (int i = 0;i < q;i++)
  108. {
  109. ans = 0;
  110. int a,b;
  111. scanf("%d%d",&a,&b);
  112. query2(a,b,1,u,1);
  113. printf("%d\n",ans);
  114. }
  115. return 0;
  116. }

C. Karen and Game
题意:
一个游戏,每次可以对一行上的所有数加1或者对每一列上的数加1,现在给出结果矩阵,问最少多少次操作可以把结果矩阵得出来。
思路:
找每一行的最小值,如果不是0,就把这行的每个数减去这个最小值,然后每一列也这么干。
第一次wa,是因为找的不是最小次数。
试想
1 1 1
1 1 1
1 1 1
1 1 1
这个矩阵,如果说先横着来的话,那么答案是4,但是答案是3,所以后来改进,先横后竖,先竖后横,两种的次数比较一下就可以了,中间的操作用队列记录一下。
代码:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <queue>
  4. using namespace std;
  5. int a[105][105];
  6. int w[105][105];
  7. typedef pair<char,int> p;
  8. queue<p> q1;
  9. queue<int> qq1;
  10. queue<p> q2;
  11. queue<int> qq2;
  12. int main()
  13. {
  14. int n,m;
  15. scanf("%d%d",&n,&m);
  16. for (int i = 1;i <= n;i++)
  17. for (int j = 1;j <= m;j++)
  18. {
  19. scanf("%d",&a[i][j]);
  20. w[i][j] = a[i][j];
  21. }
  22. bool f = 0;
  23. int ans1 = 0;
  24. for (int i = 1;i <= n;i++)
  25. {
  26. int minn = 600;
  27. for (int j = 1;j <= m;j++)
  28. {
  29. if (minn > a[i][j]) minn = a[i][j];
  30. }
  31. if (minn >= 1)
  32. {
  33. qq1.push(minn);
  34. ans1 += minn;
  35. q1.push(p('r',i));
  36. for (int j = 1;j <= m;j++)
  37. a[i][j] -= minn;
  38. }
  39. }
  40. for (int i = 1;i <= m;i++)
  41. {
  42. int minn = 600;
  43. for (int j = 1;j <= n;j++)
  44. {
  45. if (a[j][i] < minn) minn = a[j][i];
  46. }
  47. if (minn >= 1)
  48. {
  49. qq1.push(minn);
  50. ans1 += minn;
  51. q1.push(p('c',i));
  52. for (int j = 1;j <= n;j++)
  53. a[j][i] -= minn;
  54. }
  55. }
  56. int ans2 = 0;
  57. for (int i = 1;i <= m;i++)
  58. {
  59. int minn = 600;
  60. for (int j = 1;j <= n;j++)
  61. {
  62. if (w[j][i] < minn) minn = w[j][i];
  63. }
  64. if (minn >= 1)
  65. {
  66. qq2.push(minn);
  67. ans2 += minn;
  68. q2.push(p('c',i));
  69. for (int j = 1;j <= n;j++)
  70. w[j][i] -= minn;
  71. }
  72. }
  73. for (int i = 1;i <= n;i++)
  74. {
  75. int minn = 600;
  76. for (int j = 1;j <= m;j++)
  77. {
  78. if (minn > w[i][j]) minn = w[i][j];
  79. }
  80. if (minn >= 1)
  81. {
  82. qq2.push(minn);
  83. ans2 += minn;
  84. q2.push(p('r',i));
  85. for (int j = 1;j <= m;j++)
  86. w[i][j] -= minn;
  87. }
  88. }
  89. for (int i = 1;i <= n;i++)
  90. for (int j = 1;j <= m;j++)
  91. {
  92. if (a[i][j] != 0) f = 1;
  93. }
  94. if (f) printf("-1\n");
  95. else
  96. {
  97. if (ans1 > ans2)
  98. {
  99. printf("%d\n",ans2);
  100. while (!q2.empty())
  101. {
  102. p t = q2.front();q2.pop();
  103. int ti = qq2.front();qq2.pop();
  104. char c = t.first;
  105. int po = t.second;
  106. if (c == 'r')
  107. {
  108. for (int i = 1;i <= ti;i++)
  109. printf("row %d\n",po);
  110. }
  111. if (c == 'c')
  112. {
  113. for (int i = 1;i <= ti;i++)
  114. printf("col %d\n",po);
  115. }
  116. }
  117. }
  118. else
  119. {
  120. printf("%d\n",ans1);
  121. while (!q1.empty())
  122. {
  123. p t = q1.front();q1.pop();
  124. int ti = qq1.front();qq1.pop();
  125. char c = t.first;
  126. int po = t.second;
  127. if (c == 'r')
  128. {
  129. for (int i = 1;i <= ti;i++)
  130. printf("row %d\n",po);
  131. }
  132. if (c == 'c')
  133. {
  134. for (int i = 1;i <= ti;i++)
  135. printf("col %d\n",po);
  136. }
  137. }
  138. }
  139. }
  140. return 0;
  141. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注