考虑将相邻的相等的数缩成一个数。
假设没有分成了$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 }