Problem

洛谷5156

题意概要:给定一个长为\(n\)的排列,可以选择一个集合\(S\)使这个集合内部元素排到自己在整个序列中应该在的位置(即对于集合\(S\)内的每一个元素\(i\),使其排到第\(i\)号位置,使得整个排列在排序后为上升序列。求满足这样条件的,且集合大小最小的集合中字典序第\(k\)小的集合(可能总结不到位,看链接里的吧)

\(n\leq 10^5\)

Solution

不难发现出题人费尽心思写的题面就是在强烈暗示选取一个集合等价于将这个集合内所有元素排到自己该处于的位置(即元素\(i\)应该在位置\(i\))

进一步发现集合内的元素很自觉的到了正确的位置,而集合外的元素不会更改相对位置,为了使最终整个排列单调递增,即要求集合外的元素必须满足在一开始就是单调递增的

求字典序第\(k\)小的满足题意的集合,取反一下,就是求序列中字典序第\(k\)大的最长上升子序列

(至此题目模型转化完成)


现在目标为求字典序第\(k\)大的最长上升子序列

在继续之前建议先将最长递增子序列的数量解决:

设置\(f_i\)表示以权值为\(i\)结尾的\(LIS\)的长度和数量,则权值\(x\)从\(f_1...f_{x-1}\)间转移,用树状数组维护前缀最大值和数量即可\(O(n\log n)\)解决


利用上面这题的思想,已经可以求得以每个元素开头的\(LIS\)长度和数量

这题和上面这题虽有不同,但本质类似,想想一般线段树求第 \(k\) 大的过程,正是依次确定每一层的节点,而为了确定每一层的节点,就需要用到所有节点子树和

同理,假设当前要求的序列的\(LIS\)长度为 \(t\),则求第\(k\)大\(LIS\)的一个思想就是先确定第\(1\)个数,再在确定第\(1\)个数的基础上确定下一个数……以此类推可以最终确定\(LIS\)的每一位

细化一下,就是将所有可能作为\(LIS\)的第\(i\)位的数 放进第\(i\)个vector里,将每个vector内部进行元素排序,在确定每一位时从大到小确定,若当前值后面牵扯的\(LIS\)数量小于\(k\),则将\(k\)减去这个数量然后检查下一个值,否则将这个值确定下来并开始确认下一位

(值得注意的一点,若求\(LIS\)第\(i\)层选定了位置\(R\)的元素,则接下来都不能选择\(R\)左边的元素)

Code

关于代码中的一些疑问:

  • 我没有用vector,而是使用链式前向星替代
  • 由于每个vector里的元素一定是按照位置递增而权值递减的,所以并不需要排序
  • 很多人用线段树,而这题只需要树状数组即可
  • 在求完以每个点开始的\(LIS\)后树状数组就没用了,可以节约大量时间
#include <bits/stdc++.h>
typedef long long ll; inline void read(int&x){
char c11=getchar();x=0;while(!isdigit(c11))c11=getchar();
while(isdigit(c11))x=x*10+c11-'0',c11=getchar();
} const int N=101000;
struct Edge{int v,nxt;}e[N];
int a[N],chs[N],head[N];
int n,_;ll k; const ll lim=1e18; struct node{
int v;ll c;
inline node(){}
friend inline void operator + (node&A,const node B){
if(A.v<B.v)A.v=B.v,A.c=B.c;
else if(A.v==B.v)A.c=std::min(lim,A.c+B.c);
}
}d[N],g[N],cl; #define lb(x) (x&(-x)) inline node qy(int x){node p=cl;for(x;x<=n+1;x+=lb(x))p+d[x];return p;}
inline void add(int x,node y){for(;x;x-=lb(x))d[x]+y;}
inline void ae(int u,int v){e[++_].v=v,e[_].nxt=head[u],head[u]=_;} int main(){
scanf("%d%lld",&n,&k);
for(int i=1;i<=n;++i)read(a[i]);
cl.c=1,add(n+1,cl),cl.c=0;
for(int i=n;i;--i){
g[i]=qy(a[i]);
++g[i].v;
add(a[i],g[i]);
}
for(int i=n;i;--i)ae(g[i].v,i);
for(int stp=qy(1).v,R=0;stp;--stp)
for(int i=head[stp],v;i;i=e[i].nxt){
v=e[i].v;
if(g[v].c<k)k-=g[v].c;
else {
chs[a[v]]=true;
while(R<v)g[R++]=cl;
break;
}
}
printf("%d\n",n-qy(1).v);
for(int i=1;i<=n;++i)
if(!chs[i])printf("%d\n",i);
return 0;
}

题解-USACO18DEC Sort It Out的更多相关文章

  1. 题解-USACO18DEC Balance Beam详细证明

    (翻了翻其他的题解,觉得它们没讲清楚这个策略的正确性) Problem 洛谷5155 题意概要:给定一个长为\(n\)的序列,可以选择以\(\frac 12\)的概率进行左右移动,也可以结束并得到当前 ...

  2. LeetCode题解之Sort List

    1.题目描述 2.问题分析 使用sort算法 3.代码 ListNode* sortList(ListNode* head) { if( head == NULL || head->next = ...

  3. [LeetCode 题解]: Insertion Sort List

    Sort a linked list using insertion sort. 题目要求:链表的插入排序,由于没有时间复杂度的要求,可以直接循环操作. /** * Definition for si ...

  4. [USACO18DEC]Sort It Out(树状数组)

    [Luogu5156] 题解 求字典序第 k 小的满足题意的集合,取反一下,就是求序列中字典序第 k 大的最长上升子序列 [51nod1376] 最长递增子序列的数量 置 \(f_{i}\)表示以权值 ...

  5. [USACO18DEC]Sort It Out P

    初看本题毫无思路,只能从特殊的 \(K = 1\) 出发. 但是直接考虑构造一组字典序最小的方案还是不好构造,可以考虑先手玩一下样例.通过自己手玩的样例可以发现,貌似没有被选出来的数在原排列中都是递增 ...

  6. PAT甲题题解-1067. Sort with Swap(0,*) (25)-贪心算法

    贪心算法 次数最少的方法,即:1.每次都将0与应该放置在0位置的数字交换即可.2.如果0处在自己位置上,那么随便与一个不处在自己位置上的数交换,重复上一步即可.拿样例举例:   0 1 2 3 4 5 ...

  7. 洛谷P5156 [USACO18DEC]Sort It Out

    这题就是让你求字典序第k小的最短乱序子序列 转换一下,其实就是字典序第k大的最长上升子序列 就统计一下以i结尾的最长上升子序列\(f[i]\),长度为i的上升子序列的开头组成的集合\(v[i]\),转 ...

  8. p5156 [USACO18DEC]Sort It Out

    传送门 分析 我们发现对于没有发现的点相对位置不会发生改变 于是我们可以吧问题转化为求一个lis 于是我们字典序第k小的答案就是字典序第k大的lis 代码 #include<iostream&g ...

  9. 题解 [USACO18DEC]Balance Beam

    被概率冲昏的头脑~~~ 我们先将样例在图上画下来: 会发现,最大收益是: 看出什么了吗? 这不就是凸包吗? 跑一遍凸包就好了呀,这些点中,如果i号点是凸包上的点,那么它的ans就是自己(第二个点),不 ...

随机推荐

  1. java io系列12之 BufferedInputStream(缓冲输入流)的认知、源码和示例

    本章内容包括3个部分:BufferedInputStream介绍,BufferedInputStream源码,以及BufferedInputStream使用示例. 转载请注明出处:http://www ...

  2. netty的拆包和粘包

    第一种:自定义规则 比如说我们自己设定$_结尾的数据为一个整体. 看主要代码,大体不变,就多了几行代码.具体先看我上一篇的代码.这里只做修改 server端 b.childHandler(new Ch ...

  3. vscode Live Server使用

    vscode 的Live Server插件可以开启本地服务器

  4. Emacs 快速指南(中文翻译)

      Emacs 快速指南 目录 1. 小结(SUMMARY) 2. 基本的光标控制(BASIC CURSOR CONTROL) 3. 如果 EMACS 失去响应(IF EMACS STOPS RESP ...

  5. Linux 命令详解(十二)Systemd 入门教程:使用定时器发送邮件(mail)

    Systemd 定时器教程:http://www.ruanyifeng.com/blog/2018/03/systemd-timer.html 一.定时任务 Systemd 定时任务:每小时发送一封电 ...

  6. npm与yarn命令对比

    Yarn是由Facebook.Google.Exponent 和 Tilde 联合推出了一个新的 JS 包管理工具 Yarn 是为了弥补 npm 的一些缺陷而出现的(比如,npm install时候会 ...

  7. chart.js angular组件封装(ng6)、实战配置、插件编写

    前言 项目需要使用chart.js插件,由于项目是使用angular开发,那么我第一步就是先把chart.js改造成angular组件来使用. 本项目代码都可以在github上下载:项目git地址 a ...

  8. 使用模拟Table解决span重叠问题

    <div id="test"> <div > <span>adfafadsfadfa</span> <span style=& ...

  9. 导入numpy时,出错怎么解决?

    在linux中导入numpy时出错,出现如下图所示的问题,采用更新版本的问题并未解决, 解决方法如下:进入文件夹中,删除其中的numpy文件夹,其他的文件夹不动,然后重新安装numpy即可

  10. qt5下载与安装,VS2017的环境配置

    下载地址  http://download.qt.io/archive/qt/ 安装 选择安装路径 ,只有没有中文即可 二.Qt与VS2017相关联 1.打开VS2017,选择工具 - 拓展和更新 2 ...