题目传送

学习的这篇题解

结论:

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了,一下砍下去一段。

 #pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cctype>
#include <climits>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <string>
#include <sstream>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <list>
#include <fstream>
#include <bitset>
#define init(a, b) memset(a, b, sizeof(a))
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define irep(i, a, b) for (int i = a; i >= b; i--)
using namespace std; typedef double db;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;
const int inf = 0x3f3f3f3f;
const ll INF = 1e18; template <typename T> void read(T &x) {
x = ;
int s = , c = getchar();
for (; !isdigit(c); c = getchar())
if (c == '-') s = -;
for (; isdigit(c); c = getchar())
x = x * + c - ;
x *= s;
} template <typename T> void write(T x) {
if (x < ) x = -x, putchar('-');
if (x > ) write(x / );
putchar(x % + '');
} template <typename T> void writeln(T x) {
write(x);
puts("");
} const int maxn = 1e5 + ;
const ll maxk = 1e18; int n, a[maxn];
ll k;
struct Arr {
int len;
ll cnt;
Arr() {
len = , cnt = ;
}
Arr(int a, ll b) {
len = a, cnt = b;
}
}dp[maxn], bit[maxn];
vector<int> v[maxn];
bool mark[maxn]; void Modify(Arr &a, Arr b) {
if (a.len > b.len) return;
if (a.len < b.len) {
a = b;
return;
}
a.cnt = min(maxk, a.cnt + b.cnt);
} void Update(int x, Arr val) {
for (; x; x -= x&-x)
Modify(bit[x], val);
} Arr Query(int x) {
Arr ret(, );
for (; x <= n; x += x&-x)
Modify(ret, bit[x]);
return ret;
} int main() {
read(n), read(k);
rep(i, , n) read(a[i]);
//树状数组维护一个后缀最大序列(的长度和此长度下的LIS个数),规则是:1.长度最大;2.如果长度相同,累加数量
irep(i, n, ) {//比较字典序是从左往右,所以将此长度下的cnt集中在左端,故而倒序
dp[i] = Query(a[i] + );
v[++dp[i].len].push_back(i);
Update(a[i], dp[i]);
} int LIS = Query().len;
for (int i = LIS, pos = ; i; --i) {
for (int j = v[i].size() - ; ~j; --j) {
//找字典序大的,所以倒着找。vector的插入导致其中的a[p]必然升序
int p = v[i][j];
if (dp[p].cnt < k) {//以当前数字为开头的所有LIS的数量都无法满足k的需求,则这个开头被pass
k -= dp[p].cnt;
} else {//说明要找的LIS以当前这个数字为开头
mark[a[p]] = true;
while (pos < p) dp[pos++].cnt = ;
//选定这个数以后,因为是找LIS,所以它之前的数不能再选中
break;
}
}
} writeln(n - LIS);
rep(i, , n) {
if (!mark[i])
writeln(i);
}
return ;
}

BZOJ5484(LIS性质+树状数组)的更多相关文章

  1. nlogn求LIS(树状数组)

    之前一直是用二分 但是因为比较难理解,写的时候也容易忘记怎么写. 今天比赛讲评的时候讲了一种用树状数组求LIS的方法 (1)好理解,自然也好写(但代码量比二分的大) (2)扩展性强.这个解法顺带求出以 ...

  2. 「BZOJ1669」D 饥饿的牛 [Usaco2006 Oct] Hungry Cows 牛客假日团队赛5 (LIS,离散化树状数组)

    链接:https://ac.nowcoder.com/acm/contest/984/D 来源:牛客网 饥饿的牛 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言 ...

  3. UvaLive 6667 Longest Chain (分治求三元组LIS&amp;树状数组)

    题目链接: here 题意: 和hdu4742类似.差别就是一部分三元组是直接给出的.另一部分是用他给的那个函数生成的.还有就是这里的大于是严格的大于a>b必须ax>bx,ay>by ...

  4. Dynamic Inversions II 逆序数的性质 树状数组求逆序数

    Dynamic Inversions II Time Limit: 6000/3000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Other ...

  5. [noip科普]关于LIS和一类可以用树状数组优化的DP

    预备知识 DP(Dynamic Programming):一种以无后效性的状态转移为基础的算法,我们可以将其不严谨地先理解为递推.例如斐波那契数列的递推求法可以不严谨地认为是DP.当然DP的状态也可以 ...

  6. Codeforces 486E LIS of Sequence --树状数组求LIS

    题意: 一个序列可能有多个最长子序列,现在问每个元素是以下三个种类的哪一类: 1.不属于任何一个最长子序列 2.属于其中某些但不是全部最长子序列 3.属于全部最长子序列 解法: 我们先求出dp1[i] ...

  7. 【Codeforces】Gym 101156E Longest Increasing Subsequences LIS+树状数组

    题意 给定$n$个数,求最长上升子序列的方案数 根据数据范围要求是$O(n\log n)$ 朴素的dp方程式$f_i=max(f_j+1),a_i>a_j$,所以记方案数为$v_i$,则$v_i ...

  8. poj1631——树状数组求LIS

    题目:http://poj.org/problem?id=1631 求LIS即可,我使用了树状数组. 代码如下: #include<iostream> #include<cstdio ...

  9. HDU1087(树状数组求LIS)

    题是水题,学习一下用树状数组求LIS. 先离散化一下,注意去重:然后就把a[i]作为下标,dp[i]作为值,max作为维护的运算插进树状数组即可. 如果是上升子序列,询问(a[i] - 1):如果是不 ...

随机推荐

  1. UltraEdit中使用正则表达式-简单用法

    UltraEdit中使用正则表达式 1.认识正则表达式语法: 正则表达式 (UltraEdit Syntax): % 匹配行首 - 表明要搜索的字符串一定在行首. $ 匹配行尾 - 表明要搜索的字符串 ...

  2. 【ACdream】1157 Segments cdq分治

    Segments   Problem Description 由3钟类型操作:1)D L R(1 <= L <= R <= 1000000000) 增加一条线段[L,R]2)C i ...

  3. 在C语言中使用libiconv进行编码转换的示例

    libiconv_sample.c #include <stdio.h> #include <malloc.h> #include "libiconv/iconv.h ...

  4. android 中的常用组件

    gradle gradle 是个啥,一开始我也没弄清,官方解释是: Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化建构工具 那么Apache Ant和Apache ...

  5. Mac OS X 开发环境搭建之利用 Parallel Desktop 安装 CentOS 7 [转载]

    背景 在企业级软件系统中,数据库的地位是比较高的,而且一般都要求支持多种数据库,如 Oracle. DB2.MySQL 等,它们的最新版本大多都不再支持 Mac OS X 系统,所以装一个 Linux ...

  6. 基于MATLAB的滤波算法

    目前比较经典的图像去噪算法主要有以下三种: 均值滤波:也称线性滤波,主要思想为邻域平均法,即用几个像素灰度  的平均值来代替每个像素的灰度.有效抑制加性噪声,但容易引起图像模糊,  可以对其进行改进, ...

  7. android adb 源码框架分析(1 系统)【转】

    本文转载自:http://blog.csdn.net/luansxx/article/details/25203269 ‘ Adb模块包括adb,adbd,源代码都在system/core/adb目录 ...

  8. linux初级学习笔记六:linux用户及权限详解!(视频序号:03_4)

    本节学习的命令:/etc/passwd,/etc/shadow,/etc/group文件详解 本节学习的技能: 安全上下文 文件与目录的权限管理 影子命令 用户,用户组类别详解 /etc/passwd ...

  9. android广播接收器

    Android程序创建广播接收器继承BroadcastReceiver Android广播接收器需要在AndroidManifest.xml文件中声明: <recevie android:nam ...

  10. I.MX6 lcd lvds 注册流程

    /************************************************************************ * I.MX6 lcd lvds 注册流程 * 说明 ...