zoukankan      html  css  js  c++  java
  • BZOJ5484(LIS性质+树状数组)

    题目传送

    学习的这篇题解

    结论:

    1.直观感受一下会发现找到LIS,LIS里的东西相对位置是不会变的,其他的移一移总会排序成功的,所以其他的就是最小集合了,第一问的答案就是n-LIS;

    2.寻找字典序第k小的集合,相当于是寻找字典序第k大的LIS,然后把这个LIS删去,就是第二问的答案集合。

    前置技能:

    树状数组,及树状数组求LIS。

    解决方法(请先看代码):

    1.树状数组bit[i]求LIS的同时再维护一下“以比i大的数字为开头、这个LIS长度下的序列的数量”。数量超过maxk的时候min一下砍掉(是一种常见手法),因为多了也没有用它只会询问maxk以内的,否则有可能爆longlong。

    2.用vector存下每个长度的LIS是以哪些位置为起点,然后按长度从大到小枚举,看看第k个是哪个LIS,标记这些数字。因为之前维护了数量,所以这时就不用从1开始一个一个枚举到k了,一下砍下去一段。

      1 #pragma comment(linker, "/STACK:1024000000,1024000000")
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cstdlib>
      5 #include <cmath>
      6 #include <ctime>
      7 #include <cctype>
      8 #include <climits>
      9 #include <iostream>
     10 #include <iomanip>
     11 #include <algorithm>
     12 #include <string>
     13 #include <sstream>
     14 #include <stack>
     15 #include <queue>
     16 #include <set>
     17 #include <map>
     18 #include <vector>
     19 #include <list>
     20 #include <fstream>
     21 #include <bitset>
     22 #define init(a, b) memset(a, b, sizeof(a))
     23 #define rep(i, a, b) for (int i = a; i <= b; i++)
     24 #define irep(i, a, b) for (int i = a; i >= b; i--)
     25 using namespace std;
     26 
     27 typedef double db;
     28 typedef long long ll;
     29 typedef unsigned long long ull;
     30 typedef pair<int, int> P;
     31 const int inf = 0x3f3f3f3f;
     32 const ll INF = 1e18;
     33 
     34 template <typename T> void read(T &x) {
     35     x = 0;
     36     int s = 1, c = getchar();
     37     for (; !isdigit(c); c = getchar())
     38         if (c == '-')    s = -1;
     39     for (; isdigit(c); c = getchar())
     40         x = x * 10 + c - 48;
     41     x *= s;
     42 }
     43 
     44 template <typename T> void write(T x) {
     45     if (x < 0)    x = -x, putchar('-');
     46     if (x > 9)    write(x / 10);
     47     putchar(x % 10 + '0');
     48 }
     49 
     50 template <typename T> void writeln(T x) {
     51     write(x);
     52     puts("");
     53 }
     54 
     55 const int maxn = 1e5 + 5;
     56 const ll maxk = 1e18;
     57 
     58 int n, a[maxn];
     59 ll k;
     60 struct Arr {
     61     int len;
     62     ll cnt;
     63     Arr() {
     64         len = 0, cnt = 0;
     65     }
     66     Arr(int a, ll b) {
     67         len = a, cnt = b;
     68     }
     69 }dp[maxn], bit[maxn];
     70 vector<int> v[maxn];
     71 bool mark[maxn];
     72 
     73 void Modify(Arr &a, Arr b) {
     74     if (a.len > b.len)    return;
     75     if (a.len < b.len) {
     76         a = b;
     77         return;
     78     }
     79     a.cnt = min(maxk, a.cnt + b.cnt);
     80 }
     81 
     82 void Update(int x, Arr val) {
     83     for (; x; x -= x&-x)
     84         Modify(bit[x], val);
     85 }
     86 
     87 Arr Query(int x) {
     88     Arr ret(0, 1);
     89     for (; x <= n; x += x&-x)
     90         Modify(ret, bit[x]);
     91     return ret;
     92 }
     93 
     94 int main() {
     95     read(n), read(k);
     96     rep(i, 1, n)    read(a[i]);
     97     //树状数组维护一个后缀最大序列(的长度和此长度下的LIS个数),规则是:1.长度最大;2.如果长度相同,累加数量
     98     irep(i, n, 1) {//比较字典序是从左往右,所以将此长度下的cnt集中在左端,故而倒序
     99         dp[i] = Query(a[i] + 1);
    100         v[++dp[i].len].push_back(i);
    101         Update(a[i], dp[i]);
    102     }
    103 
    104     int LIS = Query(1).len;
    105     for (int i = LIS, pos = 1; i; --i) {
    106         for (int j = v[i].size() - 1; ~j; --j) {
    107         //找字典序大的,所以倒着找。vector的插入导致其中的a[p]必然升序
    108             int p = v[i][j];
    109             if (dp[p].cnt < k) {//以当前数字为开头的所有LIS的数量都无法满足k的需求,则这个开头被pass
    110                 k -= dp[p].cnt;
    111             } else {//说明要找的LIS以当前这个数字为开头
    112                 mark[a[p]] = true;
    113                 while (pos < p)    dp[pos++].cnt = 0;
    114                 //选定这个数以后,因为是找LIS,所以它之前的数不能再选中
    115                 break;
    116             }
    117         }
    118     }
    119 
    120     writeln(n - LIS);
    121     rep(i, 1, n) {
    122         if (!mark[i])
    123             writeln(i);
    124     }
    125     return 0;
    126 }
  • 相关阅读:
    CF750D New Year and Fireworks
    raw,qcow2虚拟磁盘挂载
    虚拟机嵌套kvm/vmware
    CentOS Linux 7硬盘安装
    文本界面听歌神器--moc
    Ubuntu14.04升级内核3.14.25
    (转)MySQL初识-架构-安装-初始化-连接-管理工具-数据文件
    Ubuntu14.04使用国内163源或sohu源
    虚拟磁盘格式转换(raw,qcow2,vmdk等)--qemu-img
    phpMyAdmin4.2.12安装配置
  • 原文地址:https://www.cnblogs.com/AlphaWA/p/10557099.html
Copyright © 2011-2022 走看看