CF1097E Egor and an RPG game
最少反链划分数 = 最长链。实现:每次找出所有极大元作为一个反链。
任意长度小于k * (k + 1) / 2的排列都能被划分为不多于k个单调序列。且这是一个紧的上界。
然后这题就可以切了。
题意:给定长为n的排列,设任长为n的排列都能被划分为不多于k个单调序列,把给定排列划分为不多于k个单调序列。
解:先求出k,然后求LIS,如果LIS >= k那么扔掉LIS递归。否则划分成反链即可。用链表实现。
1 #include <bits/stdc++.h> 2 3 const int N = 100010, INF = 0x3f3f3f3f; 4 5 int p[N], cnt; 6 std::vector<int> v[N]; 7 8 struct Node { 9 int nex, pre; 10 }node[N]; int tp, head = N - 1, tail = N - 2; 11 12 int stk[N], top, f[N], rest, stk2[N], fr[N]; 13 bool vis[N]; 14 15 inline void del(int x) { 16 int nex = node[x].nex, pre = node[x].pre; 17 node[nex].pre = pre; 18 node[pre].nex = nex; 19 return; 20 } 21 22 inline int getLIS() { 23 top = 0; 24 for(int i = node[head].nex; i != tail; i = node[i].nex) { 25 int l = 0, r = top; 26 while(l < r) { 27 int mid = (l + r + 1) >> 1; 28 if(stk[mid] < p[i]) { 29 l = mid; 30 } 31 else { 32 r = mid - 1; 33 } 34 } 35 f[i] = r + 1; 36 fr[i] = stk2[r]; 37 stk[r + 1] = p[i]; 38 stk2[r + 1] = i; 39 if(r == top) ++top; 40 } 41 return top; 42 } 43 44 inline void erase() { 45 int x = stk2[top]; 46 ++cnt; 47 while(x) { 48 del(x); 49 v[cnt].push_back(p[x]); 50 x = fr[x]; 51 } 52 std::reverse(v[cnt].begin(), v[cnt].end()); 53 return; 54 } 55 56 inline void split() { 57 58 while(rest) { 59 ++cnt; 60 int last = -1; 61 for(int i = node[tail].pre; i != head; i = node[i].pre) { 62 if(p[i] > last) { 63 v[cnt].push_back(i); 64 last = p[i]; 65 //printf("inside %d \n", i); 66 rest--; 67 } 68 } 69 std::reverse(v[cnt].begin(), v[cnt].end()); 70 int len = v[cnt].size(); 71 for(int i = 0; i < len; i++) { 72 del(v[cnt][i]); 73 //printf("now : %d \n", v[cnt][i]); 74 v[cnt][i] = p[v[cnt][i]]; 75 //printf("now : %d \n", v[cnt][i]); 76 } 77 } 78 79 return; 80 } 81 82 inline void solve() { 83 int n; 84 scanf("%d", &n); 85 for(int i = 1; i <= n; i++) { 86 scanf("%d", &p[i]); 87 node[i].nex = 0; 88 if(i > 1) { 89 node[i].pre = i - 1; 90 node[i - 1].nex = i; 91 } 92 else { 93 node[i].pre = head; 94 node[head].nex = i; 95 } 96 } 97 node[n].nex = tail; 98 node[tail].pre = n; 99 cnt = 0; 100 rest = n; 101 int K = 1; 102 while(K * (K + 1) / 2 <= n) { 103 ++K; 104 } 105 //printf("K = %d \n", K); 106 /// use K-1 107 while(rest) { 108 int len = getLIS(); 109 //printf("len = %d \n", len); 110 if(len >= K) { 111 erase(); 112 K--; 113 rest -= len; 114 } 115 else { 116 split(); 117 rest = 0; 118 } 119 } 120 printf("%d \n", cnt); 121 for(int i = 1; i <= cnt; i++) { 122 int len = v[i].size(); 123 printf("%d ", len); 124 for(int j = 0; j < len; j++) { 125 printf("%d ", v[i][j]); 126 } 127 puts(""); 128 v[i].clear(); 129 } 130 tp = 0; 131 return; 132 } 133 134 int main() { 135 136 int T; 137 scanf("%d", &T); 138 while(T--) { 139 solve(); 140 } 141 142 return 0; 143 }