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. HDFS 概述

    定义 HDFS(Hadoop Distributed File System)是分布式文件管理系统中的一种,用来管理多台机器上的文件,通过目录树来定位文件. 由很多服务器联合起来实现其功能,集群中的服 ...

  2. 如何比较一个类型【模板使用】【sizeof用法】

    #include <iostream> using namespace std; void testEmptyClass(); struct Empty { }; struct Dummy ...

  3. 049、准备overlay网络实验环境(2019-03-14 周四)

    参考https://www.cnblogs.com/CloudMan6/p/7270551.html   为了支持容器跨主机通信,Docker提供了overlay driver,使用户可以创建基于Vx ...

  4. Ubuntu swap

    问:我是一个Ubuntu 14.04 LTS版本的新手.我需要一块额外的swap文件来提高我Ubuntu服务器的性能.我怎样才能通过SSH连接用相关命令为我的Ubuntu 14.04 LTS 增加一块 ...

  5. HttpService

    // // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler ...

  6. ****** 三十四 ******、软设笔记【存储器系统】-Cache存储器

    Cache存储器 Cache(高速缓冲存储器) 高速缓冲存储器是位于主存与CPU之间的一级存储器,有静态存储芯片(SRAM)组成,容量比较小,速度比主存高得多,接近于CPU的速度,单位成本比内存高.C ...

  7. ubuntu 18.04 安装 Redis

    这篇博客写得不错,直接看这篇博客就OK了. https://wangxin1248.github.io/linux/2018/07/ubuntu18.04-install-redis.html

  8. Vue项目在表单中限制输入数字

    <template> <div> <input v-model="userPhone" autofocus type="text" ...

  9. LOJ #2527 Luogu P4491「HAOI2018」染色

    好像网上没人....和我推出....同一个式子啊..... LOJ #2527 Luogu P4491 题意 $ n$个格子中每个格子可以涂$ m$种颜色中的一种 若有$ k$种颜色恰好涂了$ s$格 ...

  10. 生成器的throw和close方法

    def gen_func(): try: yield 1 except Exception as e: pass yield 2 yield 3 yield 4 yield 5 return &quo ...