Advertisement
erek1e

The Collection Caper - BIO 2024 Round 2

Apr 28th, 2024
710
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 2.71 KB | None | 0 0
  1. /**
  2.  * @file caper.cpp
  3.  * @version 1.0
  4.  * @date 2024-04-03
  5.  *
  6.  * usage:
  7.  *      Read from / write to default input.txt and output.txt
  8.  *          caper.exe
  9.  *      Read from / write to custom files:
  10.  *          caper.exe in.txt out.txt
  11.  */
  12. #include <iostream>
  13. #include <vector>
  14. #include <algorithm>
  15.  
  16. using namespace std;
  17.  
  18. void fileIO(int argc, char *argv[]);
  19.  
  20. const int INF = 1e5;
  21.  
  22. int minMovesToErase(vector<int> v) {
  23.     int n = v.size();
  24.    
  25.     vector<vector<int>> dp(1+n, vector<int>(1+n));
  26.     v.push_back(0);
  27.     /*
  28.     dp[l][r] is the minimum number of moves to erase the range v[l], v[l+1], ..., v[r-1]
  29.     (excluding r), given that only elements from the same collection as v[r] can remain
  30.     */
  31.  
  32.     /*
  33.     It can be shown that for any block of values from the same collection that are initially
  34.     consecutive, it can be shown that all optimal solutions will erase them all in one step.
  35.     I use this to slightly simplify the code, though the main concept of the solution does not
  36.     depend on it.
  37.     */
  38.  
  39.     for (int sz = 1; sz <= n; ++sz) {
  40.         for (int l = 0; l+sz <= n; ++l) {
  41.             int r = l+sz;
  42.             dp[l][r] = INF;
  43.             int canLeave = v[r];
  44.            
  45.             // case: do not erase the first element
  46.             if (v[l] == canLeave) dp[l][r] = min(dp[l][r], dp[l+1][r]);
  47.            
  48.             // case: erase the first element
  49.  
  50.             int firstBlockR = l;
  51.             while (firstBlockR < r && v[firstBlockR] == v[l]) ++firstBlockR;
  52.             //  subcase: erase the first element in its own block (if the block size is >= 2)
  53.             if (firstBlockR-l >= 2) dp[l][r] = min(dp[l][r], 1 + dp[firstBlockR][r]);
  54.  
  55.             //  subcase: erase the first element along with another block
  56.             for (int i = firstBlockR, lastDifferent = firstBlockR; i < r; ++i) {
  57.                 if (v[i] == v[l] && (i+1 == r || v[i+1] != v[l])) { // a block with from the same collection as v[l] ends at i
  58.                     int lastBlockL = lastDifferent+1, lastBlockR = i+1;
  59.                     dp[l][r] = min(dp[l][r], 1 + dp[firstBlockR][lastBlockL] + dp[lastBlockR][r]);
  60.                 } else if (v[i] != v[l]) lastDifferent = i;
  61.             }
  62.         }
  63.     }
  64.     return dp[0][n];
  65. }
  66.  
  67. int main(int argc, char *argv[]) {
  68.     fileIO(argc, argv); // remove for standard input/output
  69.    
  70.     int n; cin >> n;
  71.     vector<int> a(n);
  72.     for (int &x : a) cin >> x;
  73.     cout << minMovesToErase(a) << '\n';
  74.     return 0;
  75. }
  76.  
  77. void fileIO(int argc, char *argv[]) {
  78.     const char * in = "input.txt", * out = "output.txt";
  79.     if (argc > 1) in = argv[1];
  80.     if (argc > 2) out = argv[2];
  81.     freopen(in, "r", stdin);
  82.     freopen(out, "w", stdout);
  83. }
  84.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement