设 (f(n)) 表示最小的正整数 (k),使得所有长为 (n) 的排列都可以被划分为至多 (k) 个单调子序列。
给定长为 (n) 的排列 (p),构造将其划分为至多 (f(n)) 个单调子序列的方案。(T) 组数据。
(sum nle 10^5)。
结论:
[f(n)=maxleft{kleft|frac{k(k+1)}{2}le n
ight.
ight}
]
证明:设 (c(n)) 是上式右边的值。我们可以构造 (p={1,3,2,6,5,4,cdots}),也即分成 (c(n)) 组下降子段,每组长度比上一组长 (1),只能划分为至少 (c(n)) 个单调子序列。可以得到 (f(n)ge c(n))。然后我们考虑对所有 (p) 构造划分为至多 (c(n)) 个单调子序列的方法。
求出现在的 LIS,设其长度为 (l),若 (l>c(n)),直接划分为一组,因为 (c(n-c(n)-1)le c(n)-1),所以转化为了更小的情况,可以归纳证明。
若 (lle c(n)),根据 Dilworth 定理,可以将其划分为 (l) 个下降子序列,实现方法可以用类似二分求 LIS 的方法,维护一些末尾单调上升的下降子序列,每次将 (p_i) 放进第一个末尾比 (p_i) 大的子序列。然后构造完就做完了,时间复杂度 (O(nsqrt nlog n)),还顺便得到了 (f(n)=c(n))。
#include<bits/stdc++.h>
#define PB emplace_back
#define MP make_pair
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef vector<int> vi;
typedef pair<int, int> pii;
const int N = 100003, mod = 998244353;
template<typename T>
void read(T &x){
int ch = getchar(); x = 0; bool f = false;
for(;ch < '0' || ch > '9';ch = getchar()) f |= ch == '-';
for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
if(f) x = -x;
} template<typename T>
bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
int t, n, a[N]; bool vis[N]; pii tr[N];
void upd(int p, pii v){for(;p <= n;p += p & -p) chmax(tr[p], v);}
pii qry(int p){pii res; for(;p;p -= p & -p) chmax(res, tr[p]); return res;}
vector<vi> ans, res; int from[N];
void solve(){ read(n); ans.clear(); memset(vis, 0, n+1);
for(int i = 1;i <= n;++ i) read(a[i]);
int k = 0; while((k*(k+1)>>1) <= n) ++ k;
while(k --){
memset(tr, 0, n+1<<3);
for(int i = 1;i <= n;++ i) if(!vis[i]){
pii tt = qry(a[i]); from[i] = tt.se;
upd(a[i], MP(tt.fi+1, i));
} pii tt = qry(n);
if(tt.fi <= k){ res.clear();
for(int i = 1;i <= n;++ i) if(!vis[i]){
if(res.empty() || a[i] > res.back().back()) res.push_back({a[i]});
else {
int l = 0, r = res.size()-1;
while(l < r){
int mid = l+r>>1;
if(a[i] > res[mid].back()) l = mid+1;
else r = mid;
} res[l].PB(a[i]);
}
} for(auto &u : res) ans.PB(u); break;
} vi lis;
for(int i = tt.se;i;i = from[i]){lis.PB(a[i]); vis[i] = true;}
reverse(lis.begin(), lis.end()); ans.PB(lis);
} printf("%llu
", ans.size());
for(auto &u : ans){ printf("%llu", u.size());
for(int _ : u) printf(" %d", _);
putchar('
');
}
} int main(){read(t); while(t --) solve();}