1. 程式人生 > >Codeforces Hello 2019 E

Codeforces Hello 2019 E

題目連結: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)\)

,空間複雜度\(O(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;
}