Advertisement
erek1e

The Thing - BIO 2024 Round 2

Apr 11th, 2024
731
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.13 KB | None | 0 0
  1. /**
  2.  * @file thing.cpp
  3.  * @version 1.0
  4.  * @date 2024-03-30
  5.  *
  6.  * usage:
  7.  *      Read from / write to default input.txt and output.txt
  8.  *          thing.exe
  9.  *      Read from / write to custom files:
  10.  *          thing.exe in.txt out.txt
  11.  */
  12. #include <iostream>
  13. #include <vector>
  14. #include <algorithm>
  15. #include <bitset>
  16. #include <set>
  17. #include <cassert>
  18.  
  19. using namespace std;
  20.  
  21. void fileIO(int argc, char *argv[]);
  22.  
  23. const int n = 1024; // n*n grid; solution assumes n is not very small (e.g. n > 10)
  24.  
  25. bitset<n+1> grid[n+1]; // adding ones to allow overflows without errors
  26. int countParity[2];
  27. set<pair<int, int>> sorted[2];
  28. set<pair<int, int>> movedAway;
  29.  
  30. inline void add(int x, int y) {
  31.     grid[x][y] = true;
  32.     sorted[(x+y)&1].emplace(x, y);
  33.     ++countParity[(x+y)&1];
  34. }
  35. inline void remove(int x, int y) {
  36.     grid[x][y] = false;
  37.     sorted[(x+y)&1].erase({x, y});
  38.     --countParity[(x+y)&1];
  39.     if (movedAway.count({x, y})) movedAway.erase({x, y});
  40. }
  41. inline void annihilate(int x, int y, bool inX) {
  42.     assert(grid[x][y]);
  43.     remove(x, y);
  44.     if (inX) {
  45.         assert(grid[x+1][y]);
  46.         remove(x+1, y);
  47.         cout << "H " << x << ' ' << y << '\n';
  48.     } else {
  49.         assert(grid[x][y+1]);
  50.         remove(x, y+1);
  51.         cout << "V " << x << ' ' << y+1 << '\n';
  52.     }
  53. }
  54. inline void annihilate(int x1, int y1, int x2, int y2) {
  55.     assert(abs(x1-x2) + abs(y1-y2) == 1);
  56.     annihilate(min(x1, x2), min(y1, y2), x1!=x2);
  57. }
  58. inline void clean() {
  59.     // remove any adjacent pairs
  60.     for (int x = 0; x < n; ++x) {
  61.         for (int y = 0; y < n; ++y) {
  62.             if (grid[x][y]) {
  63.                 if (grid[x][y+1]) annihilate(x, y, false);
  64.                 else if (grid[x+1][y]) annihilate(x, y, true);
  65.             }
  66.         }
  67.     }
  68. }
  69. inline void expand(int x, int y) {
  70.     assert(0 < x && x+1 < n && 0 < y && y+1 < n && grid[x][y]);
  71.     assert(!grid[x][y-1] && !grid[x-1][y] && !grid[x+1][y] && !grid[x][y+1]);
  72.     remove(x, y);
  73.     add(x-1, y), add(x, y-1), add(x+1, y), add(x, y+1);
  74.     cout << "E " << x << ' ' << y << '\n';
  75. }
  76. inline bool canMoveTwo(int x, int y, int dx, int dy) {
  77.     if (!grid[x][y] || grid[x+1][y] || grid[x][y+1] || grid[x][y-1] || grid[x-1][y]) return false;
  78.     int x0 = x, y0 = y, x1 = x, y1 = y;
  79.     if (dx) x0 += dx, x1 += dx, y0 -= 1, y1 += 1;
  80.     else x0 -= 1, x1 += 1, y0 += dy, y1 += dy;
  81.     if (grid[x0][y0] || grid[x1][y1] || grid[x+dx+dx][y+dy+dy]) return false;
  82.     return true;
  83. }
  84. inline void moveTwo(int x, int y, int dx, int dy) {
  85.     assert(canMoveTwo(x, y, dx, dy));
  86.     expand(x, y);
  87.     expand(x+dx, y+dy);
  88.     annihilate(x, y, x-dx, y-dy);
  89.     if (dx) {
  90.         annihilate(x, y+1, x+dx, y+1);
  91.         annihilate(x, y-1, x+dx, y-1);
  92.     } else {
  93.         annihilate(x+1, y, x+1, y+dy);
  94.         annihilate(x-1, y, x-1, y+dy);
  95.     }
  96. }
  97. inline bool comfortablyIn(int x, int y) {
  98.     return x-2 >= 0 && y-2 >= 0 && x+2 < n && y+2 < n;
  99. }
  100. inline pair<int, int> occupiedSurrounding(int x, int y) {
  101.     int x2 = x, y2 = y;
  102.     if (grid[x-1][y]) x2-=1;
  103.     else if (grid[x+1][y]) x2+=1;
  104.     else if (grid[x][y-1]) y2-=1;
  105.     else if (grid[x][y+1]) y2+=1;
  106.     else x2 = -1, y2 = -1;
  107.     return {x2, y2};
  108. }
  109. void cancelPair() {
  110.     auto [xa, ya] = *prev(sorted[0].end());
  111.     auto [xb, yb] = *prev(sorted[1].end());
  112.     int a = 0, b = 1;
  113.     if (make_pair(xa, ya) > make_pair(xb, yb)) {
  114.         swap(a, b);
  115.         swap(xa, xb);
  116.         swap(ya, yb);
  117.     }
  118.  
  119.     if (!movedAway.count({xb, yb})) {
  120.         moveTwo(xb, yb, +1, 0); // separate (xb, yb) from the rest
  121.         xb += 2;
  122.         movedAway.emplace(xb, yb);
  123.     }
  124.    
  125.     // move (xa, ya) towards (xb, yb)
  126.     while (abs(xa-xb) + abs(ya-yb) > 1) {
  127.         // move vertically first
  128.         int dx = +1, dy = 0;
  129.         if (xa >= xb-1) {
  130.             dx = 0;
  131.             dy = yb > ya ? +1 : -1;
  132.         }
  133.         if (canMoveTwo(xa, ya, dx, dy)) {
  134.             moveTwo(xa, ya, dx, dy);
  135.             xa += 2*dx, ya += 2*dy;
  136.         } else {
  137.             // none of the same colour should be in the way since we move vertically first
  138.             // so there is a cell of opposite colour
  139.             auto [xb2, yb2] = occupiedSurrounding(xa, ya);
  140.             assert(xb2 != -1);
  141.             // annihilate with that instead
  142.             annihilate(xa, ya, xb2, yb2);
  143.             break;
  144.         }
  145.     }
  146.     if (grid[xa][ya]) annihilate(xa, ya, xb, yb);
  147. }
  148.  
  149. int main(int argc, char *argv[]) {
  150.     fileIO(argc, argv); // remove for standard input/output
  151.    
  152.     ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  153.  
  154.     int c; cin >> c;
  155.     for (int i = 0; i < c; ++i) {
  156.         int x, y; cin >> x >> y;
  157.         add(x, y);
  158.     }
  159.     int option = abs(countParity[0]-countParity[1]) % 5;
  160.     cout << min(option, 5-option) << endl;
  161.     clean();
  162.    
  163.     if ((!countParity[0] || !countParity[1]) && countParity[0] + countParity[1] <= 2) return 0;
  164.  
  165.     // move everything up once if they are not too close to the boundary
  166.     set<pair<int, int>>::iterator it[2]{sorted[0].begin(), sorted[1].begin()};
  167.     while (it[0] != sorted[0].end() || it[1] != sorted[1].end()) {
  168.         int par = 1;
  169.         if (it[1] == sorted[1].end() || (it[0] != sorted[0].end() && *it[0] < *it[1])) {
  170.             par = 0;
  171.         }
  172.         auto [x, y] = *it[par];
  173.         ++it[par];
  174.         if (comfortablyIn(x-2, y) && canMoveTwo(x, y, -1, 0)) {
  175.             moveTwo(x, y, -1, 0);
  176.         }
  177.     }
  178.  
  179.     // now the last four rows should be empty
  180.     if (countParity[0]) assert(prev(sorted[0].end())->first < n-4);
  181.     if (countParity[1]) assert(prev(sorted[1].end())->first < n-4);
  182.  
  183.     while ((countParity[0] && countParity[1]) || countParity[0] + countParity[1] > 2) {
  184.         if (countParity[0] && countParity[1]) cancelPair();
  185.         else {
  186.             int a = sorted[0].empty() ? 1 : 0;
  187.             auto [x, y] = *prev(sorted[a].end());
  188.             expand(x, y);
  189.         }
  190.     }
  191.     return 0;
  192. }
  193.  
  194. void fileIO(int argc, char *argv[]) {
  195.     const char * in = "input.txt", * out = "output.txt";
  196.     if (argc > 1) in = argv[1];
  197.     if (argc > 2) out = argv[2];
  198.     freopen(in, "r", stdin);
  199.     freopen(out, "w", stdout);
  200. }
  201.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement