LightOJ 1277 Looking for a Subsequence (LIS)

来源:互联网 发布:mac文明5秘籍 编辑:程序博客网 时间:2024/05/24 04:28

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1277

题意:给出一个长度为n的数列。输出数列一个长度恰好为m的下标字典序最小的(即最靠左的)上升子列。

思路:从右向左求一次最长递减子列,记录每个位置的dp值,即以该数结尾最长的下降子列的长度。

对于给定的m,先从左向右找到一个dp[i]>=m的位置,那么这个数肯定是答案的第一个,输出它,然后向右找一个大于这个数且dp[j]>=m-1的数输出,依次类推。。。

这个题用普通的O(n^2)的算法会超时,用二分查找优化到 O(nlogn)

#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>using namespace std;const int N=100010;int data[N],dp[N],stack[N];int n,m,maxlen; void LIS (){int top=1;    stack[top]=data[1];    dp[1]=1;    for (int i=2;i<=n;i++)    {        if (stack[top]>data[i])        {            stack[++top]=data[i];            dp[i]=top;        }else{int low=1,high=top;while (low < high){int mid = (low+high)>>1;if (data[i] < stack[mid])low=mid+1;elsehigh=mid;}stack[low]=data[i];dp[i]=low;}    }    maxlen=top;}void Output (){int i,pre;for (i=n;i>=1;i--)if (dp[i]>=m){printf("%d",data[i]);m--;pre=data[i];break;}for (;m;i--)if (data[i]>pre && dp[i]>=m){printf(" %d",data[i]);m--;pre=data[i];}printf("\n");} int main (){#ifdef ONLINE_JUDGE#elsefreopen("read.txt","r",stdin);#endifint T,q,i;scanf("%d",&T);for (int Cas=1;Cas<=T;Cas++){scanf("%d%d",&n,&q);for (i=1;i<=n;i++)scanf("%d",&data[n-i+1]);printf("Case %d:\n",Cas);memset(dp,0,sizeof(dp));memset(stack,0,sizeof(stack));LIS ();for (i=0;i<q;i++){scanf("%d",&m);if (maxlen<m){printf("Impossible\n");continue;}Output();}}return 0;}


原创粉丝点击