BZOJ 1046 [HAOI2007]上升序列 DP

不知道什么印象,好像以前见过,记得要把数列倒过来的~

nlogn的最长上升子序列。

但是方案不好搞~

PS:看好是谁的字典序最小。。。

换个问题,

假设知道以a[i]为开头的最长下降子序列的长度,是不是就好搞了?

方法是从左往右,直接贪心的选这个i(以a[i]为开头的最长下降子序列的长度要大于你需要的长度)一定是能使字典序最小~

前面说了,倒过来做就行了, 因为我们只会求以a[i]结尾的最长上升子序列的长度。。。

 

 

View Code
 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <cstdlib>
 5 #include <algorithm>
 6 
 7 #define N 111111
 8 #define INF 0x3f3f3f3f
 9 #define BUG system("pause")
10 
11 using namespace std;
12 
13 int n,a[N],b[N],dp[N];
14 int len,stk[N],p,cas,m;
15 
16 inline void read()
17 {
18     scanf("%d",&n);
19     for(int i=n;i>=1;i--) scanf("%d",&a[i]);
20 }
21 
22 inline void step1()
23 {
24     len=1;
25     for(int i=0;i<=n;i++) b[i]=-INF;
26     b[0]=INF; b[1]=a[1]; dp[1]=1;
27     for(int i=2;i<=n;i++)
28     {
29         int l=0,r=len+1,mid,res;
30         while(l<=r)
31         {
32             mid=(l+r)>>1;
33             if(b[mid]>a[i]) res=mid,l=mid+1;
34             else r=mid-1;
35         }
36         len=max(res+1,len);
37         b[res+1]=max(b[res+1],a[i]);
38         dp[i]=res+1;
39     }
40     reverse(a+1,a+1+n);
41     reverse(dp+1,dp+1+n);
42 }
43 
44 inline void step2()
45 {
46     if(len<m) {puts("Impossible");return;}
47     p=0;
48     int last=-INF;
49     for(int i=1;i<=n&&m!=0;i++)
50         if(dp[i]>=m&&a[i]>last) stk[++p]=i,m--,last=a[i];
51     for(int i=1;i<p;i++) printf("%d ",a[stk[i]]);
52     printf("%d\n",a[stk[p]]);
53 }
54 
55 inline void go()
56 {
57     step1();
58     scanf("%d",&cas);
59     while(cas--)
60     {
61         scanf("%d",&m);
62         step2();
63     }
64 }
65 
66 int main()
67 {
68     read(),go();
69     return 0;
70 }

 

 

 

posted @ 2013-03-12 23:37  proverbs  阅读(1012)  评论(0编辑  收藏  举报