• 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 
    ", 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 
    ", v[cnt][i]);
     74             v[cnt][i] = p[v[cnt][i]];
     75             //printf("now : %d 
    ", 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 
    ", K);
    106     /// use K-1 
    107     while(rest) {
    108         int len = getLIS();
    109         //printf("len = %d 
    ", 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 
    ", 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 }
    AC代码
  • 相关阅读:
    Reference Counting GC (Part two :Partial Mark & Sweep)
    Reference Counting GC (Part one)
    Union File System
    Linux Cgroups
    Mark Sweep GC
    取模运算
    负数取模怎么算
    牛客【2021寒假集训营第一场】J-一群小青蛙呱蹦呱蹦呱
    记codeforces一个简单模拟题
    筛法求素数
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/11070477.html
Copyright © 2020-2023  润新知