USACO 2018 December Contest Platinum T2: Sort It Out

题目大意

FJ有 N1N1e5 )头奶牛(分别用 1N 编号)排成一行。FJ喜欢他的奶牛以升序排列,不幸的是现在她们的顺序被打乱了。在过去FJ曾经使用一些诸如“冒泡排序”的开创性的算法来使他的奶牛排好序,但今天他想偷个懒。取而代之,他会每次对着一头奶牛叫道“按顺序排好”。当一头奶牛被叫到的时候,她会确保自己在队伍中的顺序是正确的(从她的角度看来)。当有一头紧接在她右边的奶牛的编号比她小,她们就交换位置。然后,当有一头紧接在她左边的奶牛的编号比她大,她们就交换位置。这样这头奶牛就完成了“按顺序排好”,在这头奶牛看来左边的奶牛编号比她小,右边的奶牛编号比她大。

FJ想要选出这些奶牛的一个子集,然后遍历这个子集,依次对着每一头奶牛发号施令(按编号递增的顺序),重复这样直到所有N头奶牛排好顺序。例如,如果她选出了编号为 {2,4,5} 的奶牛的子集,那么他会喊叫奶牛2,然后是奶牛4,然后是奶牛5。如果 N 头奶牛此时仍未排好顺序他会再次对着这几头奶牛喊叫,如果有必要的话继续重复。

由于FJ不确定哪些奶牛比较专心,他想要使得这个子集最小。此外,他认为 K 是个幸运数字。请帮他求出满足重复喊叫可以使得所有奶牛排好顺序的最小子集之中字典序第 K 小的子集。

我们称 {1,,N} 的一个子集 S 在字典序下小于子集 T ,当 S 的所有元素组成的序列(按升序排列)在字典序下小于 T 的所有元素组成的序列(按升序排列)。例如, {1,3,6} 在字典序下小于 {1,4,5} 。

题目分析

观察题目,考虑一直对某个集合里的元素一直发号施令会产生什么结果。显然易见,该集合里的所有元素都最终会被排到自己那个最“合适”的位置,而集合外部的元素顺序不会改变。

 

既然我们要让全部元素从小到大排列,我们要让 选中集合 外部的元素有序。

这样的话,我们必须先求出 “选中集合 外部的元素有序” 的个数。显然,这就是个LIS问题。

 

设置结构体 Fi​ 表示以权值为 i 结尾的 LIS的长度和数量,则可以从权值在 从 ​~ i1间转移过来,用树状数组维护前缀最大值和数量即可O(logn)时间内解决。

 回到本题,我们可以先用类似的方法,求出以每个点开头的LIS的最长长度和数量。这需要我们倒过来DP,并用树状数组维护后缀和而非前缀和。

 

在求出这些以后,我们从前往后扫一遍,把每个元素按以它开头的LIS长度,放到n个vector里。(为什么是n个,因为可能序列本身就是有序,长度为n)

然后我们按长度推。对于每个长度,依次遍历这个vector(已经字典序从大到小了),如果当前位置i开头的LIS数量num(i)<k,则k-=num(i),否则我们要选的就是当前位。

注意选了位置i以后,小于i的位置都不能再选,需要把这些位置的LIS数量清零。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const ll Inf=1e18+10;
 5 const int MAXN=1e5+10;
 6 
 7 ll k;
 8 int n;
 9 int a[MAXN];
10 
11 struct Node{
12     int len;ll num;
13     Node(int len_=0,ll num_=0){len=len_;num=num_;}
14 }BIT[MAXN],f[MAXN];
15 
16 
17 inline void Work(Node &x,Node y){
18     if(x.len>y.len) return;
19     if(x.len<y.len) x=y;
20     else x.num=min(Inf,x.num+y.num); 
21 }
22 inline int lowbit(int x){
23     return x&(-x);
24 }
25 inline void Update(int x,Node y){
26     for(int i=x;i;i-=lowbit(i))
27         Work(BIT[i],y);
28 }
29 inline Node Query(int x){
30     Node res=Node(0,1);
31     for(int i=x;i<=n;i+=lowbit(i))
32         Work(res,BIT[i]);
33     return res;
34 }
35 vector<int> v[MAXN];
36 bool used[MAXN];
37 int main(){
38     scanf("%d%lld",&n,&k);
39     for(int i=1;i<=n;++i)
40         scanf("%d",&a[i]);
41     for(int i=n;i>=1;--i){
42         f[i]=Query(a[i]+1);
43         f[i].len++;
44         Update(a[i],f[i]);
45     }
46     for(int i=1;i<=n;++i)
47         v[f[i].len].push_back(i);
48     for(int len=Query(1).len,r=1;len>=1;--len){
49         for(int i=0;i<(int)v[len].size();++i){
50             int tmp=v[len][i];
51             if(f[tmp].num<k) k-=f[tmp].num;
52             else{
53                 used[a[tmp]]=1;
54                 while(r<=tmp) f[r++].num=0;
55                 break;
56             }
57         }
58     }
59     printf("%d\n",n-Query(1).len);
60     for(int i=1;i<=n;++i)
61         if(!used[i])
62             printf("%d\n",i);
63     return 0;
64 }

 

转载于:https://www.cnblogs.com/LI-dox/p/11217096.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: USACO 2021年12月是美国计算机奥林匹克竞赛的一次比赛,是为了选拔美国高中生中最优秀的计算机科学家而举办的。比赛包括四个不同难度级别的编程题目,参赛者需要在规定时间内完成这些题目。这次比赛的题目难度较高,需要参赛者具备较强的编程能力和算法思维能力。 ### 回答2: usaco是一个很受欢迎的美国高中生和大学生参加的计算机竞赛,每年会有四场不同的赛事,分为铜组、银组、金组和白银组等4个不同级别。2021年12月的usaco比赛题目难度中等,共4道算法题,主要涉及搜索算法、贪心算法、动态规划和图论算法等方面内容。 题目一是“Convenience Store”,给定一个城市地图,其中包含n个建筑,每个建筑位置有xy坐标,建筑之间可能有道路连通,每个建筑中包含一个便利店和售货员,售货员需要把货物直接送到顾客的门口并统计物资,问售货员需要访问哪些建筑才能完成任务。 题目二是“Longest Path Game”,给定一个有向无环图和起点和终点,每次可以走向图中指向该点的其他点,每走一步需要支付一定的代价,问从起点到终点最少需要支付多少代价并给出最少花费路径。 题目三是“Escape”,给定一个大小为n*m的迷宫,其中包含空地和只能通过特殊方式通过的障碍物,新增一个道具可以消除障碍物,在指定时间内到达终点即可获胜,问是否存在可行解。 题目四是“New Year Travel”,给定一个n个城市构成的圆环和m条单向道路,初次n个城市顺时针排列,经过m次之后重排该圆环,问是否存在一条路径可以在经过圆环的最小路程的前提下遍历所有的城市。 ### 回答3: USACO 2021 12月是一次由美国计算机科学奥林匹克联赛(USACO)组织的编程竞赛。USACO是美国高中生最具影响力的计算机竞赛之一,每年分为四个季度,包含铜组、银组、金组和白金组,涵盖了算法设计、数据结构、图论、搜索、动态规划、计算几何、图像处理等多个领域和真实场景。 本场比赛共有铜组、银组和金组三个组别,其中铜组和银组为在线比赛,金组为24小时比赛。比赛难度较高且时间较紧,需要选手在有限时间内完成一系列复杂的程序设计题目。在比赛期间,选手需要具备良好的分析问题、设计算法和编写程序的能力,同时还需要有过硬的数学基础、英语阅读理解能力和编程实践经验。 对于铜组选手来说,需要能够熟练使用基本算法和数据结构来解决题目,如模拟、暴力搜索、递推等;对于银组选手,则需要有更深入的算法思考和程序实现能力,如分治、贪心、二分、动态规划等;而针对金组选手,需要更高的算法挑战和程序优化能力,如图论、网络流、计算几何等。 此次USACO 2021 12月比赛题目难度较大,需要选手们具备扎实的算法基础和良好的程序设计习惯。要想在比赛中取得好成绩,需要选手们克服紧张心理,在比赛前加强对算法知识和代码实践的学习,时刻保持冷静,清晰思路,在有限时间内充分展现自己的编程才能和思维能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值