Codeforces Hello 2019 E
阿新 • • 發佈:2019-01-07
題目連結:https://codeforces.com/contest/1097/problem/E
(本題中部分結論作者也不會證明,讀者可以自行打表理解)
考慮對於最小的\(k\)使得\(\frac{k(k+1)}{2}>n\)則任意\(n\)個數的排列一定可以分成\(k-1\)個單調子序列,考慮該序列的最長上升子序列的長度,設為\(\mid LIS \mid\),若\(\mid LIS \mid \geq k\),則直接將它取出將問題變成一個\(n-k\)規模的問題,否則我們將序列分成\(\mid LIS \mid\)個下降子序列,其中一定有一個的長度大於等於\(k\),直接取出即可,用樹狀陣列求最長上升子序列即可。
時間複雜度\(O(n\sqrt n\log_2 n)\)
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> #include <iostream> #include <algorithm> #include <stack> #include <queue> #include <map> #include <set> #include <iomanip> #include <assert.h> #include <fstream> using namespace std; const int MAXN = 100005; int T,n; int a[MAXN]; int pre[MAXN]; bool mark[MAXN]; pair<int,int> MAX[MAXN]; vector<vector<int> > ans; int getlim(int N) { int low = 0,high = 500; while (low < high) { int mid = (low + high) >> 1; if (mid * (mid + 1) / 2 >= N) high = mid; else low = mid + 1; } return low; } void modify(int p,pair<int,int> v) { while (p <= n) { if (v.first > MAX[p].first) MAX[p] = v; p += (p & -p); } } pair<int,int> query(int p) { pair<int,int> res; while (p >= 1) { if (MAX[p].first > res.first) res = MAX[p]; p -= (p & -p); } return res; } int main() { ios::sync_with_stdio(false); cin >> T; while (T--) { ans.clear(); cin >> n; for (int i = 1;i <= n;i++) cin >> a[i]; int N = n; while (N) { int lk = getlim(N); for (int i = 1;i <= n;i++) MAX[i] = make_pair(0,0); for (int i = 1;i <= N;i++) mark[i] = false; pair<int,int> res,MAXF; for (int i = 1;i <= N;i++) { res = query(a[i]); res.first++; pre[i] = res.second; res.second = i; if (res.first > MAXF.first) MAXF = res; modify(a[i],make_pair(res.first,i)); } if (MAXF.first >= lk) { int cur = MAXF.second; vector<int> seq; while (cur) { mark[cur] = true; seq.push_back(a[cur]); cur = pre[cur]; } ans.push_back(seq); } else { vector<int> seq; for (int i = N;i >= 1;i--) if (!seq.size() || seq.back() < a[i]) { mark[i] = true; seq.push_back(a[i]); } ans.push_back(seq); } int tmp = 0; for (int i = 1;i <= N;i++) if (!mark[i]) a[++tmp] = a[i]; N = tmp; } cout << ans.size() << endl; for (int i = 0;i < ans.size();i++) { cout << ans[i].size() << ' '; while (ans[i].size()) { cout << ans[i].back() << ' '; ans[i].pop_back(); } cout << endl; } } return 0; }