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 }
posted @ 2019-01-07 12:17  阿波罗2003  阅读(240)  评论(0编辑  收藏  举报