LightOJ 1277 Looking for a Subsequence(LIS)

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

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

思路:从右向左求一次最长递减子列,记录每个位置的f值,即以该数结尾最长的下降子列。对于给定的m,先从左向右找到一个f[i]>=m的位置,那么这个数肯定是答案的第一个,输出它,然后向右找一个大于这个数且f[j]>=m-1的数输出,依依次类推。。。

 

 #include <iostream>

 #include <cstdio>

 using namespace std;

 

 

 

 const int MAX=100005;

 int C,num=0;

 int n,Q,m,f[MAX],cNum,c[MAX],a[MAX];

 

 

 void DP()

 {

     int i,mid,low,high;

 

     cNum=0;c[++cNum]=a[1];f[1]=1;

     for(i=2;i<=n;i++)

     {

         low=1;high=cNum+1;

         while(low<high)

         {

             mid=(low+high)>>1;

             if(a[i]<c[mid]) low=mid+1;

             else high=mid;

         }

         c[high]=a[i];

         if(high==cNum+1) cNum++;

         f[i]=high;

     }

 }

 

 void deal()

 {

     int i,pre;

     for(i=n;i>=1;i--) if(f[i]>=m)

     {

         printf("%d",a[i]);

         m--;

         pre=a[i];

         break;

     }

     while(m)

     {

         while(a[--i]>pre&&f[i]>=m)

         {

             printf(" %d",a[i]);

             m--;

             pre=a[i];

             break;

         }

     }

     puts("");

 }

 

 int main()

 {

     for(scanf("%d",&C);C--;)

     {

         scanf("%d%d",&n,&Q);

         int i;

         for(i=1;i<=n;i++) scanf("%d",&a[n+1-i]);

         DP();

         printf("Case %d:\n",++num);

         while(Q--)

         {

             scanf("%d",&m);

             if(m>cNum)

             {

                 puts("Impossible");

                 continue;

             }

             deal();

         }

     }

     return 0;

 }

 

  

 

 

你可能感兴趣的:(sequence)