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. python 面向对象(四)反射

    ####################总结########## 1. isinstance: 判断xxx是否是xxx类型的(向上判断) type: 返回xx对象的数据类型 issubclass: 判 ...

  2. Linux记录-salt命令

    salt '*id*'  test.ping salt -N  组名  cmd.run '' salt -G "ipv4:0.0.0.0"  cmd.run '' salt '*i ...

  3. 在js或jquery中动态添加js脚本【转】

    起因: 我们在用js动态写入script时,会导致</script>后面的所有语句都变为普通文本,导致html展示无效, 所以我们需要规避</script>问题. 解决方案一( ...

  4. mysql 用户及权限管理 小结

    MySQL 默认有个root用户,但是这个用户权限太大,一般只在管理数据库时候才用.如果在项目中要连接 MySQL 数据库,则建议新建一个权限较小的用户来连接. 在 MySQL 命令行模式下输入如下命 ...

  5. ZOJ - 1610 Count the Colors(线段树区间更新)

    https://cn.vjudge.net/problem/ZOJ-1610 题意 给一个n,代表n次操作,接下来每次操作表示把[l,r]区间的线段涂成k的颜色其中,l,r,k的范围都是0到8000. ...

  6. 使用C#的HttpWebRequest模拟登陆网站

    很久没有写新的东西了,今天在工作中遇到的一个问题,感觉很有用,有种想记下来的冲动. 这篇文章是有关模拟登录网站方面的. 实现步骤: 启用一个web会话 发送模拟数据请求(POST或者GET) 获取会话 ...

  7. 5年GTD自我管理经验,一块听听

    我在胜利油田做了20多年的油田信息化工作,以前的我经常处于这样一种状态: 当我正在做着手边的一项事情时,头脑里却不断地蹦出来其它的事务,让我烦心不已,焦虑不安:PPT经常要拖到汇报当天的凌晨才做完,有 ...

  8. 本地测试使用Tomcat,生产环境使用GlassFish。

    总结:Tomcat8 = javaee7规范(servlet3.1 + jsp2.3 + el3.0 + websocket1.0) + java7 [配置初始化参数使用jdk8编译]conf/web ...

  9. C# EF框架调用数据库的函数

    1.在数据库中创建一个自定义函数: REATE FUNCTION [dbo].[f_IsOriginsDisabled] ( ), @needPPTV bit ) RETURNS bit AS BEG ...

  10. python面向对象和面向过程介绍与区别

    一.面向对象和面向过程的区别: a.面向过程: 1)根据业务逻辑从上到下写代码 2)开发思路是将数据和函数按照执行的逻辑顺序组织在一起 3)分开考虑数据与函数 定义性文字: 面向对象编程(Object ...