博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HAOI 2007 上升序列
阅读量:6695 次
发布时间:2019-06-25

本文共 2129 字,大约阅读时间需要 7 分钟。

  对于一个给定的S={

a1,a2,a3,…,an},若有P={ax1,ax2,ax3,…,axm},满足(x1<x2<…<xm)且(ax1<ax2<…<axm)。那么就称PS的一个上升序列。如果有多个P满足条件,那么我们想求字典序最小的那个。

任务

    给出S序列,给出若干询问。对于第i个询问,求出长度为Li的上升序列,如有多个,求出字典序最小的那个(即首先x1最小,如果不唯一,再看x2最小……),如果不存在长度为Li的上升序列,则打印Impossible.

输入

    第一行一个N,表示序列一共有N个元素

    第二行N个数,为a1,a2,…,an

    第三行一个M,表示询问次数。下面接M行每行一个数Li,表示要询问长度为Li的上升序列。

输出

    对于每个询问,如果对应的序列存在,则输出,否则打印Impossible.

样例

lis.in

6

3 4 1 2 3 6

3

6

4

5

lis.out

Impossible

1 2 3 6

Impossible

数据范围

N<=10000

M<=1000

 

                          【算法简析】

    首先很容易发现,如果Li的长度大于这个序列的LIS的长度,那么一定无解,否则一定有解。为方便讨论,下文只考虑有解情况。

暂且抛开“字典序最小”这个限制条件,即任何长度为Li的上升序列Pi都可以看作符合要求,那么题目的所有要求都可以由LIS来满足。这样我们就可以直接求这个序列的LIS,然后对于所有m次询问,用O(n)的时间输出,这样算法总的时间复杂度就是O(nlogn+nm)

那么如果要求字典序最小又如何处理呢?其实我们完全可以在相同的时间复杂度内解决问题,只是需要一些转化。

注意到在求LIS的过程中,实际上我们得到的不只是LIS,而是每个数作为子序列末尾的所有最长上升序列。把问题换一个角度,假设我们知道以每个数a[i]作为开头的最长上升序列的长度lis[i],那么就很容易利用贪心思想构造出答案了。这个贪心成立的前提就是:只要以该元素为开头的LIS的长度大于等于Li,则一定有解。该结论是很显然的。

下面简述贪心的方法:

累加下标j,从左到右扫描序列,如果lis[j]Li,则答案序列的第Li个数就是a[j],并且Li减1。重复上述过程直到Li=0。最后将答案序列倒着输出即可。

这个贪心显然是成立的。由于j是从小到大逐次增加,所以第一个符合lis[j]Li的必然就是最优解。每次找到一个符合的元素,所需要的LIS的长度就会减少1。这样重复下去得到的必然是最优解。

由于只需要对序列做一遍扫描,时间复杂度最坏O(n)。构造答案的时间为O(nm),加上预处理求LISO(nlogn)的时间,总时间复杂度为O(nlogn+nm)

 

细节:求以a[i]为开头的LIS比较麻烦,可以把序列反过来后求以a[i]为末尾的LDSLongest Decreasing Subsequence),这样处理起来较方便。

1 #include
2 const int MAXN=100010; 3 using namespace std; 4 int n,m,cnt,a[MAXN],f[MAXN],best[MAXN]; 5 int BinarySearch(int x){ 6 int lowerBound=1,upperBound=cnt,ans=0; 7 while(lowerBound<=upperBound){ 8 int mid=(lowerBound+upperBound)/2; 9 if(best[mid]>x){10 ans=mid;11 lowerBound=mid+1;12 }13 else upperBound=mid-1;14 }15 return ans;16 }17 18 void solve(int x){19 int last=0;20 for(int i=1;i<=n;i++)21 if(f[i]>=x&&a[i]>last){22 printf("%d",a[i]);23 if(x!=1) printf(" ");24 last=a[i];25 x--;26 if(!x) break;27 }28 printf("\n");29 }30 31 void preDP(){32 for(int i=n;i>=1;i--){33 int t=BinarySearch(a[i]);34 f[i]=t+1;35 cnt=max(cnt,t+1);36 if(best[t+1]

 

转载于:https://www.cnblogs.com/CXCXCXC/p/4684734.html

你可能感兴趣的文章
初识缓存Cache
查看>>
易宝典文章——怎样管理Exchange Server 2013邮箱邮件流功能之传递选项
查看>>
学习笔记——Python」Python中的类(classes)
查看>>
如何在Windows中批量创建VMware的虚拟机
查看>>
敏捷开发采取面向对象的设计原则
查看>>
由浅入深分析mybatis通过动态代理实现拦截器(插件)的原理
查看>>
配置MySQL主从复制
查看>>
grep,egrep,fgrep的使用
查看>>
Interested Transaction List ( ITL ) in Oracle
查看>>
Spring
查看>>
C#委托基础7——匿名方法
查看>>
3. 文件系统——创建、删除分区和内核同步分区信息
查看>>
配置防火墙 允许或阻止被Ping和设置方法
查看>>
Python集合
查看>>
磁盘管理
查看>>
我的友情链接
查看>>
Centos 6.3 install Darwin Streaming Server 6.0.3
查看>>
个人博客的推广
查看>>
MVC-Easy-UI-datagrid-分页-查询
查看>>
嘉协达ARM服务器:“省”字当头
查看>>