Codeforces Gym 101623A Ascending Photo - 动态规划

题目传送门

  传送门

题目大意

  给定一个长度为$n$的序列,要求划分成最少的段数,然后将这些段排序使得新序列单调不减。

  考虑将相邻的相等的数缩成一个数。

  假设没有分成了$n$段,考虑最少能够减少多少划分。

  我们将这个序列排序,对于权值相同的一段数可以任意交换它们,每两个相邻数在原序列的位置中如果是$i, i + 1$,那么划分的段数就可以减少1.

  每次转移我们考虑添加值相同的一段。

  每次转移能不能将减少的段数加一取决于当前考虑的数在前一段内有没有出现以及有没有作为最左端点。

  因此我们记录一个决策与最优解不同的次优解就能转移了。

Code

  1 /**
  2  * Codeforces
  3  * Gym#101623A
  4  * Accepted
  5  * Time: 171ms
  6  * Memory: 18300k
  7  */
  8 #include <algorithm>
  9 #include <iostream>
 10 #include <cassert>
 11 #include <cstdlib>
 12 #include <cstdio>
 13 using namespace std;
 14 typedef bool boolean;
 15 
 16 #define pii pair<int, int>
 17 #define fi first
 18 #define sc second
 19 
 20 ostream& operator << (ostream& out, pii x) {
 21     out << "(" << x.fi << ", " << x.sc << ")";
 22     return out;
 23 }
 24 
 25 template <typename T>
 26 void pfill(T* pst, const T* ped, T val) {
 27     for ( ; pst != ped; *(pst++) = val);
 28 }
 29 
 30 template <typename T>
 31 void pcopy(T* pst, const T* ped, T *pval) {
 32     for ( ; pst != ped; *(pst++) = *(pval++));
 33 }
 34 
 35 int n;
 36 int *ar;
 37 pii *ps;
 38 
 39 inline void init() {
 40     scanf("%d", &n);
 41     ar = new int[(n + 1)];
 42     for (int i = 1; i <= n; i++)
 43         scanf("%d", ar + i);
 44 }
 45 
 46 int *ss, *st;
 47 boolean *exi;
 48 inline void solve() {
 49     ps = new pii[(n + 1)];
 50     ss = new int[(n + 1)];
 51     st = new int[(n + 1)];
 52     exi = new boolean[(n + 1)];
 53     pfill(exi, exi + n + 1, false);
 54     int m = 0, diff = 0;
 55     for (int i = 1; i <= n; i++)
 56         if (i == 1 || ar[i] != ar[i - 1])
 57             ps[++m] = pii(ar[i], ++diff);
 58     sort(ps + 1, ps + (n = m) + 1);
 59 //    for (int i = 1; i <= m; i++)
 60 //        cerr << ps[i] << endl;
 61     ss[1] = 1;
 62     for (int i = 2; i <= n; i++)
 63         ss[i] =    ((ps[i - 1].first == ps[i].first) ? (ss[i - 1]) : (i));
 64     st[n] = n;
 65     for (int i = n - 1; i; i--)
 66         st[i] = ((ps[i + 1].first == ps[i].first) ? (st[i + 1]) : (i));
 67 
 68     ss[0] = st[0] = 0;
 69     pii f(0, -1), g(-14285700, -1), cf(-1, -1), cg(-1, -1);
 70     for (int i = 1; i <= n; i++) {
 71         if (ss[i] != i)
 72             continue;
 73         for (int j = max(ss[i - 1], 1); j <= st[i - 1]; j++)
 74             exi[ps[j].second] = true;
 75         for (int j = ss[i], x, uval; j <= st[i]; j++) {
 76             x = ps[j].second;
 77             if (exi[x - 1]) {
 78                 if (x - 1 == f.second && st[i - 1] > ss[i - 1])
 79                     assert(x - 1 != g.second), uval = g.first + 1;
 80                 else
 81                     uval = f.first + 1;
 82                 uval = max(uval, f.first);
 83             } else
 84                 uval = f.first;
 85             if (uval > cf.first)
 86                 cg = cf, cf = pii(uval, x);
 87             else if (x != cg.second && uval > cg.first)
 88                 cg = pii(uval, x);
 89         }
 90         for (int j = max(ss[i - 1], 1); j <= st[i - 1]; j++)
 91             exi[ps[j].second] = false;
 92         swap(cf, f);
 93         swap(cg, g);
 94         cf = pii(-14285700, -1), cg = pii(-14285700, -1);
 95 //        cerr << f << " " << g << endl;
 96     }
 97     printf("%d\n", n - f.first - 1);
 98 }
 99 
100 int main() {
101     init();
102     solve();
103     return 0;
104 }
posted @ 2018-10-24 22:34  阿波罗2003  阅读(389)  评论(0编辑  收藏  举报