1. 程式人生 > >bzoj 3704 昊昊的機油之GRST - 貪心

bzoj 3704 昊昊的機油之GRST - 貪心

題目傳送門

  傳送門

題目大意

  給定一個數組$a$和陣列$b$,每次操作可以選擇$a$的一個子區間將其中的數在模4意義下加1,問把$a$變成$b$的最少操作次數。

  首先求$b - a$,再差分,令這個陣列為$c$。

  那麼操作的次數是這個陣列$c$中正數的和。

  現在可以做的是選擇一個地方+4,它後面的某個地方-4。

  考慮什麼時候可以使得當前的答案減少。

  • 在$-3$處$+4$,在$3$處$-4$,答案減少2
  • 在$-3$處$+4$,在$2$處$-4$,答案減少1
  • 在$-2$處$+4$,在$3$處$-4$,答案減少1

  首先我們將盡量靠後的$-3$和$3$匹配,然後將對它操作。

  這個用一個棧就能做。

  剩下就貪心一下就好了。注意當$-3$和$2$操作時會多出$-2$。

Code

  1 /**
  2  * bzoj
  3  * Problem#3704
  4  * Accepted
  5  * Time: 1400ms
  6  * Memory: 128316k
  7  */
  8 #include <iostream>
  9 #include <cstdlib>
 10 #include <cstdio>
 11 #include <queue>
 12 #include <stack>
 13
using namespace std; 14 typedef bool boolean; 15 16 typedef class Input { 17 protected: 18 const static int limit = 65536; 19 FILE* file; 20 21 int ss, st; 22 char buf[limit]; 23 public: 24 25 Input():file(NULL) { };
26 Input(FILE* file):file(file) { } 27 28 void open(FILE *file) { 29 this->file = file; 30 } 31 32 void open(const char* filename) { 33 file = fopen(filename, "r"); 34 } 35 36 char pick() { 37 if (ss == st) 38 st = fread(buf, 1, limit, file), ss = 0;//, cerr << "str: " << buf << "ed " << st << endl; 39 return buf[ss++]; 40 } 41 }Input; 42 43 #define digit(_x) ((_x) >= '0' && (_x) <= '9') 44 45 Input& operator >> (Input& in, unsigned& u) { 46 char x; 47 while (~(x = in.pick()) && !digit(x)); 48 for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0'); 49 return in; 50 } 51 52 Input& operator >> (Input& in, unsigned long long& u) { 53 char x; 54 while (~(x = in.pick()) && !digit(x)); 55 for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0'); 56 return in; 57 } 58 59 Input& operator >> (Input& in, int& u) { 60 char x; 61 while (~(x = in.pick()) && !digit(x) && x != '-'); 62 int aflag = ((x == '-') ? (x = in.pick(), -1) : (1)); 63 for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0'); 64 u *= aflag; 65 return in; 66 } 67 68 Input& operator >> (Input& in, long long& u) { 69 char x; 70 while (~(x = in.pick()) && !digit(x) && x != '-'); 71 int aflag = ((x == '-') ? (x = in.pick(), -1) : (1)); 72 for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0'); 73 u *= aflag; 74 return in; 75 } 76 77 Input& operator >> (Input& in, char* str) { 78 for (char x; ~(x = in.pick()) && x != '\n' && x != ' '; *(str++) = x); 79 return in; 80 } 81 82 Input in (stdin); 83 84 template <typename T> 85 void pfill(T* pst, const T* ped, T val) { 86 for ( ; pst != ped; *(pst++) = val); 87 } 88 89 int n; 90 int *a, *b, *c; 91 boolean *used; 92 93 inline void init() { 94 in >> n; 95 a = new int[(n + 1)]; 96 b = new int[(n + 1)]; 97 c = new int[(n + 1)]; 98 for (int i = 1; i <= n; i++) { 99 in >> a[i]; 100 } 101 for (int i = 1; i <= n; i++) { 102 in >> b[i]; 103 c[i] = (b[i] - a[i] + 4) % 4; 104 } 105 } 106 107 stack<int> sta; 108 inline void solve() { 109 int ans = 0; 110 for (int i = n; i > 1; i--) 111 c[i] = c[i] - c[i - 1]; 112 used = new boolean[(n + 1)]; 113 pfill(used, used + n + 1, false); 114 for (int i = 1; i <= n; i++) 115 if (c[i] > 0) 116 ans += c[i]; 117 for (int i = 1, y; i <= n; i++) 118 if (c[i] == -3) 119 sta.push(i); 120 else if (c[i] == 3 && !sta.empty()) { 121 y = sta.top(); 122 sta.pop(); 123 used[y] = used[i] = true; 124 ans -= 2; 125 } 126 127 int have_2 = 0, have_3 = 0; 128 for (int i = 1; i <= n; i++) { 129 if (used[i]) 130 continue; 131 switch (c[i]) { 132 case 3: 133 if (have_3) 134 have_3--, ans--; 135 else if (have_2) 136 have_2--, ans--; 137 break; 138 case 2: 139 if (have_3) 140 have_3--, have_2++, ans--; 141 break; 142 case -2: 143 have_2++; 144 break; 145 case -3: 146 have_3++; 147 break; 148 } 149 } 150 printf("%d\n", ans); 151 } 152 153 int main() { 154 init(); 155 solve(); 156 return 0; 157 }