Solution of Codeforces Round #824 — editorial

Codeforces Round #824 — editorial

1735A - Working Week

Hint1

Let's consider that l1l2, and l3 are sorted working segments. Can we explicitly say something about one of them?

Answer to Hint1

l1 must be equal to 1.

Solution

Let's consider that l1l2, and l3 are sorted working segments.

If l1 is not equal to 1 then we can decrease l1 by 1 and increase l3 by 1. So we'll increase the answer.

We've got that l1=1 and we have to work just with l2 and l3.

Now, our problem can be rewritten as:
l2+l3=n4, maximize min(l21,l3l2).

And as we know that l3=n4l2, just:
maximize min(l21,n42l2).

If we increase both values under the minimum scope by one, solutions don't change:
maximize min(l2,(n3)2l2).

If we choose l2=n33, then min(l2,(n3)2l2)=n33.
If the answer is greater, then l2>n33 and (n3)2l2>n33, and it means that 2(l2)+((n3)2l2)>n3 but 2(l2)+((n3)2l2)=n3.

The only thing is left to do is to calculate final answer. And it is n331 or just n32.

It was a mathematician way of solving. As it's pretty obvious that l2 is approximately n3, you could check l2=n3±5 and choose the best among them.

Code

174443363

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. void solve() {
  4. int n;
  5. cin >> n;
  6. int l_2 = (n - 3) / 3;
  7. int ans = l_2 - 1;
  8. cout << ans << '\n';
  9. }
  10. int main() {
  11. ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  12. int t = 1;
  13. cin >> t;
  14. while (t--)
  15. solve();
  16. return 0;
  17. }

1735B - Tea with Tangerines

Hint1

Is there a way to cut pieces to save the minimum value and satisfy required conditions?

Hint2

What is the minimum possible number of operations to perform it?
Is there any better solution?

Solution

Let's start with a simple solution.

Let's choose the minimum piece from a and assume that it will remain the minimum until the end.
As the array is sorted, let's define the minimum piece as a1.
It means that in the end, all pieces must be smaller or equal to 2a11.

The lower bound of the answer for this solution is i=1nai2a11.

Let's show that this is achievable.
For each piece, while its size greater than 2a11, let's cut off a piece of size 2a11.
The only problem is that we could get a piece smaller than a1 in the end.
But it means that before the last cut we had a piece in the range [2a1,3a12]. All pieces in this range can be easily cut into pieces of the right size in one move.

The only left question is why the minimum piece in the end should have size a1. Actually, it shouldn't, but it gives the best answer anyway.
As was described above, the lower bound of the solution with the minimal piece of size x in the end is i=1nai2x1.
Having a minimal piece with a smaller size, we can't get anything better, because the lower bound will be equal or greater for all x<a1.

Code

174443424

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int n;
  4. vector<int> a;
  5. void solve() {
  6. cin >> n;
  7. a.resize(n);
  8. int ans = 0;
  9. for (auto &i : a) {
  10. cin >> i;
  11. ans += (i - 1) / (2 * a[0] - 1);
  12. }
  13. cout << ans << '\n';
  14. }
  15. int main() {
  16. ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  17. int t = 1;
  18. cin >> t;
  19. while (t--)
  20. solve();
  21. return 0;
  22. }

1735C - Phase Shift

Hint1

What is the first letter in the answer?

Answer to Hint1

a if t doesn't start with a and b otherwise.

Hint2

Ask the same question as Hint1 for each position.

Hint3

When we can't choose the minimum unused letter?

Answer to Hint3

If we form a circle of size less then 26.
Maintain any structure to check it.

Solution

First of all, the encryption process is reversible. If we obtained t from s using the circle c, we can obtain s from t using the same cycle c, but reversed.
So, let's think in terms of encryption of t.

Lexicographical order itself is a greedy thing. So, we can create a greedy algorithm.

Let's go from left to right and generate the result letter by letter. We have to choose the best possible option at each step. Let's describe the options we have.

  • If the current letter was used earlier, we already know the replacement we need to choose.
  • Otherwise, we would like to choose the minimum possible option. We need to maintain some structure to know what is acceptable.

Let's keep the circle that is already generated(it's a graph). For each letter we have one incoming edge and one outgoing edge in the end. Let's keep them for every letter: arrays in[26]out[26].
When we want to generate an outgoing edge at some step(let's define the letter on this step as x), we have to choose the minimum letter that doesn't have an incoming edge yet. With one exception: if creating the edge using this rule creates a circle of size less than 26. It would mean that we wouldn't have a full circle in the end. It's easy to see that there is no more than one such letter, as this letter is just the end of a chain starting in x.
To check that a small circle wasn't generated, we can go along an outgoing edge 26 times, starting at x. If we end up in x or there was no edge at some step then everything is ok, we can create this edge.

Complexity is O(2626+n), that is, O(n).

Code

174443480

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int n;
  4. vector<int> a;
  5. void solve() {
  6. cin >> n;
  7. a.resize(n);
  8. int ans = 0;
  9. for (auto &i : a) {
  10. cin >> i;
  11. ans += (i - 1) / (2 * a[0] - 1);
  12. }
  13. cout << ans << '\n';
  14. }
  15. int main() {
  16. ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  17. int t = 1;
  18. cin >> t;
  19. while (t--)
  20. solve();
  21. return 0;
  22. }

1735D - Meta-set

Hint1

How many sets can fit in 5 cards?

Answer to Hint1

At most two.
If there are two sets among 5 cards, there will be a central card.
Consider each card as a central card.

Solution

For every two cards, there is always a single card that forms a set with them.
[1] That means that two sets can share at most one card.

Let's prove that there are no more than 2 sets in a meta-set.
Let's define 5 cards as c1,c2,c3,c4,c5. Let's guess that (c1,c2,c3) is a set.
All other sets can have at most one card among (c1,c2,c3) (according to [1]), so they must include c4 and c5. So we have at most one other set, otherwise they would have two same cards, which is prohibited according to [1].

So, every meta-set looks like 2 sets with one common card. Let's call this card a central card.

Now there is just a simple combinatorics. For each card, we want to know the number of sets that include it. If this number is s, then we should add s(s1)2 to the answer — it is the number of meta-sets with this card as a central card.

To get the number of sets for each card, we can iterate over all pairs of cards (i,j), generate the complement to the set, and add 1 to that card in a map/hashmap.

Complexity is O(kn2log(n)) or O(kn2).

Code

174443540

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define F first
  4. #define S second
  5. typedef long long ll;
  6. typedef long double ld;
  7. typedef pair<ll, ll> pll;
  8. typedef pair<int, int> pii;
  9. const long long kk = 1000;
  10. const long long ml = kk * kk;
  11. const long long mod = ml * kk + 7;
  12. const long long inf = ml * ml * ml + 7;
  13. #ifdef DEBUG
  14. mt19937 rng(1033);
  15. #else
  16. mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
  17. #endif
  18. int rnd(int mod) { return uniform_int_distribution<int>(0, mod - 1)(rng); }
  19. bool viv = false;
  20. int n, k;
  21. vector<vector<int>> v;
  22. vector<int> get_comp(vector<int> a, vector<int> b) {
  23. vector<int> res(k);
  24. for (int i = 0; i < k; i++)
  25. res[i] = (6 - (a[i] + b[i])) % 3;
  26. return res;
  27. }
  28. void solve() {
  29. cin >> n >> k;
  30. v.resize(n);
  31. for (auto &vec : v) {
  32. vec.resize(k);
  33. for (auto &i : vec)
  34. cin >> i;
  35. }
  36. map<vector<int>, int> cnt;
  37. for (int i = 0; i < n; i++) {
  38. for (int j = i + 1; j < n; j++) {
  39. auto comp = get_comp(v[i], v[j]);
  40. cnt[comp]++;
  41. }
  42. }
  43. ll ans = 0;
  44. for (auto vec : v) {
  45. ans += (ll)cnt[vec] * (cnt[vec] - 1) / 2;
  46. }
  47. cout << ans << '\n';
  48. }
  49. int main() {
  50. // viv = true;
  51. ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  52. cout << fixed << setprecision(20);
  53. int t = 1;
  54. // cin >> t;
  55. while (t--)
  56. solve();
  57. #ifdef DEBUG
  58. cerr << "Runtime is: " << clock() * 1.0 / CLOCKS_PER_SEC << endl;
  59. #endif
  60. }

1735E - House Planning

Hint1

How many possible options are there for the distance between p1 and p2.

Answer to Hint1

We can limit it with 2n options.
Consider options d1[1]+d2[i]|d1[1]d2[i]|. Solve each one in linear(almost) time.

Hint2

Consider the biggest distance among d1 and d2.
Can we match it with something?

Hint3

Remove them one by one while they exceed the distance between p1 and p2. Then the problem is trivial.

Solution

Let's assume that considered point p1 was to the left of considered point p2.
Let's assume that we know the distance l between considered points p1 and p2. Let's show how to solve this problem in linear time(almost linear).

As long as there is a value greater than l, let's get the largest among them(let's call it x). Let's assume that this value is from d1.
It's easy to see that this point is to the right of the considered point p2 (because the largest distances is to the point p1). It means that we can match distance x from d1 to the distance xl from d2.

When there is no value greater than l, all other houses are located between considered points. We can match them by sorting.

That is the O(nlog(n)) solution.

Let's limit possible options of l with O(n) options.
If we know that some house has distances x and y to considered options, then there are 2 options of lx+y and |xy|.
Let's consider 2n options d1[1]+d2[i]|d1[1]d2[i]|.

Complexity is O(n2log(n)).

Code

174443587

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define F first
  4. #define S second
  5. typedef long long ll;
  6. typedef long double ld;
  7. typedef pair<ll, ll> pll;
  8. typedef pair<int, int> pii;
  9. const long long kk = 1000;
  10. const long long ml = kk * kk;
  11. const long long mod = ml * kk + 7;
  12. const long long inf = ml * ml * ml + 7;
  13. #ifdef DEBUG
  14. mt19937 rng(1033);
  15. #else
  16. mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
  17. #endif
  18. int rnd(int mod) { return uniform_int_distribution<int>(0, mod - 1)(rng); }
  19. bool viv = false;
  20. int n;
  21. vector<int> d1, d2;
  22. bool work(int points_diff) {
  23. int p1 = 0;
  24. int p2 = points_diff;
  25. multiset<int, greater<int>> s1, s2;
  26. for (auto i : d1)
  27. s1.insert(i);
  28. for (auto i : d2)
  29. s2.insert(i);
  30. auto farthest = [] (multiset<int, greater<int>> &s) {
  31. return s.empty() ? -1 : *s.begin();
  32. };
  33. auto farthest_both = [&]() {
  34. return max(farthest(s1), farthest(s2));
  35. };
  36. vector<int> ans;
  37. while (farthest_both() > points_diff) {
  38. bool choose_s1 = farthest(s1) > farthest(s2);
  39. auto &s_far = choose_s1 ? s1 : s2;
  40. auto &s_near = choose_s1 ? s2 : s1;
  41. int value = *s_far.begin();
  42. int complem = value - points_diff;
  43. if (!s_near.count(complem))
  44. return false;
  45. s_far.erase(s_far.find(value));
  46. s_near.erase(s_near.find(complem));
  47. if (choose_s1)
  48. ans.push_back(p1 + value);
  49. else
  50. ans.push_back(p2 - value);
  51. }
  52. vector<int> left1, left2;
  53. for (auto i : s1)
  54. left1.push_back(i);
  55. for (auto i : s2)
  56. left2.push_back(i);
  57. sort(left1.begin(), left1.end());
  58. sort(left2.rbegin(), left2.rend());
  59. for (int i = 0; i < left1.size(); i++)
  60. if (left1[i] + left2[i] != points_diff)
  61. return false;
  62. for (auto i : left1)
  63. ans.push_back(i);
  64. sort(ans.begin(), ans.end());
  65. int sh = max(-ans[0], 0);
  66. p1 += sh, p2 += sh;
  67. for (auto &i : ans)
  68. i += sh;
  69. cout << "YES\n";
  70. for (auto i : ans)
  71. cout << i << ' ';
  72. cout << '\n';
  73. cout << p1 << ' ' << p2 << '\n';
  74. return true;
  75. }
  76. void solve() {
  77. cin >> n;
  78. d1.resize(n);
  79. d2.resize(n);
  80. for (auto &d : d1)
  81. cin >> d;
  82. for (auto &d : d2)
  83. cin >> d;
  84. int dist1 = d1[0];
  85. for (auto dist2 : d2) {
  86. if (work(dist1 + dist2))
  87. return;
  88. if (work(abs(dist1 - dist2)))
  89. return;
  90. }
  91. cout << "NO\n";
  92. }
  93. int main() {
  94. // viv = true;
  95. ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  96. cout << fixed << setprecision(20);
  97. int t = 1;
  98. cin >> t;
  99. while (t--)
  100. solve();
  101. #ifdef DEBUG
  102. cerr << "Runtime is: " << clock() * 1.0 / CLOCKS_PER_SEC << endl;
  103. #endif
  104. }

1735F - Pebbles and Beads

Solution

Will be added soon

Code

174443858

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define F first
  4. #define S second
  5. typedef long long ll;
  6. typedef long double ld;
  7. typedef pair<ll, ll> pll;
  8. typedef pair<int, int> pii;
  9. const long long kk = 1000;
  10. const long long ml = kk * kk;
  11. const long long mod = ml * kk + 7;
  12. const long long inf = ml * ml * ml + 7;
  13. const ld eps = 1e-9;
  14. #ifdef DEBUG
  15. mt19937 rng(1033);
  16. #else
  17. mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
  18. #endif
  19. int rnd(int mod) { return uniform_int_distribution<int>(0, mod - 1)(rng); }
  20. int n, a, b;
  21. vector<int> p, q;
  22. struct Seg {
  23. ll init_x, init_y;
  24. int num;
  25. ld x, y;
  26. Seg() {}
  27. Seg(int p, int q, int num): init_x(q), init_y(-p), num(num) {
  28. x = init_x;
  29. y = init_y;
  30. }
  31. friend bool operator<(const Seg &s1, const Seg &s2) {
  32. if (s1.init_x * s2.init_y == s1.init_y * s2.init_x)
  33. return s1.num < s2.num;
  34. return s1.init_x * s2.init_y < s1.init_y * s2.init_x;
  35. }
  36. Seg operator*=(ld ratio) { x *= ratio; y *= ratio; return *this; }
  37. void show() {
  38. cout << "Seg(" << x << ' ' << y << ")";
  39. }
  40. };
  41. struct Point {
  42. ld x, y;
  43. Point() {}
  44. Point(int a, int b): x(b), y(a) {}
  45. Point operator+=(const Point &v) { x += v.x; y += v.y; return *this; }
  46. Point operator-=(const Point &v) { x -= v.x; y -= v.y; return *this; }
  47. Point operator+=(const Seg &v) { x += v.x; y += v.y; return *this; }
  48. Point operator-=(const Seg &v) { x -= v.x; y -= v.y; return *this; }
  49. void show() {
  50. cout << "Point(" << x << ' ' << y << ")";
  51. }
  52. };
  53. struct Stock {
  54. Point best_a;
  55. Point best_b;
  56. multiset<Seg> segs;
  57. Stock(int a, int b) {
  58. best_a = Point(a, 0);
  59. best_b = Point(0, b);
  60. Seg seg_1 = Seg(a, 0, -2);
  61. Seg seg_2 = Seg(0, b, -1);
  62. if (a)
  63. segs.insert(seg_1);
  64. if (b)
  65. segs.insert(seg_2);
  66. }
  67. void add_seg(int p, int q, int num) {
  68. Seg new_seg = Seg(2 * p, 2 * q, num);
  69. segs.insert(new_seg);
  70. Point shift(p, -q);
  71. best_a += shift;
  72. best_b -= shift;
  73. cut_left();
  74. cut_down();
  75. }
  76. void cut_left() {
  77. while (best_a.x < 0) {
  78. Seg l_seg = *segs.begin();
  79. Point new_best_a = best_a;
  80. new_best_a += l_seg;
  81. if (new_best_a.x > eps) {
  82. ld ratio = new_best_a.x / l_seg.x;
  83. Seg l_seg_left = l_seg;
  84. l_seg_left *= ratio;
  85. segs.erase(segs.find(l_seg));
  86. segs.insert(l_seg_left);
  87. new_best_a -= l_seg_left;
  88. new_best_a.x = max(new_best_a.x, (ld)0);
  89. } else {
  90. segs.erase(segs.begin());
  91. }
  92. best_a = new_best_a;
  93. }
  94. }
  95. void cut_down() {
  96. while (best_b.y < 0) {
  97. Seg d_seg = *segs.rbegin();
  98. Point new_best_b = best_b;
  99. new_best_b -= d_seg;
  100. if (new_best_b.y > eps) {
  101. ld ratio = new_best_b.y / -d_seg.y;
  102. Seg d_seg_left = d_seg;
  103. d_seg_left *= ratio;
  104. segs.erase(segs.find(d_seg));
  105. segs.insert(d_seg_left);
  106. new_best_b += d_seg_left;
  107. new_best_b.y = max(new_best_b.y, (ld)0);
  108. } else {
  109. segs.erase(segs.find(d_seg));
  110. }
  111. best_b = new_best_b;
  112. }
  113. }
  114. void print_best() {
  115. cout << best_a.y << '\n';
  116. }
  117. void show() {
  118. cout << "----\tStock\t----\n";
  119. cout << "best_a = ";
  120. best_a.show();
  121. cout << endl;
  122. Point cur = best_a;
  123. for (auto seg : segs) {
  124. cur += seg;
  125. cout << "\t";
  126. cur.show();
  127. cout << endl;
  128. }
  129. cout << "best_b = ";
  130. best_b.show();
  131. cout << endl;
  132. cout << "----\tEnd\t----\n\n";
  133. }
  134. };
  135. void solve() {
  136. cin >> n >> a >> b;
  137. p.resize(n);
  138. q.resize(n);
  139. for (int i = 0; i < n; i++)
  140. cin >> p[i];
  141. for (int i = 0; i < n; i++)
  142. cin >> q[i];
  143. Stock st(a, b);
  144. for (int i = 0; i < n; i++) {
  145. st.add_seg(p[i], q[i], i);
  146. st.print_best();
  147. }
  148. }
  149. int main() {
  150. ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  151. cout << fixed << setprecision(20);
  152. int t = 1;
  153. cin >> t;
  154. while (t--)
  155. solve();
  156. #ifdef DEBUG
  157. cerr << "Runtime is: " << clock() * 1.0 / CLOCKS_PER_SEC << endl;
  158. #endif
  159. }

Comments

Popular posts from this blog

Whiteboarding Interviews

Version Control with Git: A Beginner’s Guide

Callback function in JavaScript