【bzoj1046】[HAOI2007]上升序列

首先求出以每个数为开头上升序列长度,即倒着做最长下降子序列

然后,把字典序尽量小的放前面

即若要求的序列长度为x,如果以第一个数(字典序最小的数)开头的最长上升子序列大等于x,则将它放在答案第一个,第二个数开头小于x,则舍弃,第三个大于x-1,放答案第二个,以此类推

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 using namespace std;
 8  
 9 typedef long long LL;
10  
11 #ifdef WIN32
12 #define orz "%lld"
13 #else
14 #define orz "%I64d"
15 #endif
16  
17 #define MAXN 10010
18 int f[MAXN],a[MAXN],b[MAXN];
19 int n,m;
20 int ans;
21 int x;
22  
23 void work(int x)
24 {
25     int res=0;
26     for (int i=1;i<=n;i++)
27         if (f[i]>=x && a[i]>res)
28         {
29             printf("%d",a[i]);
30             if (x!=1)
31                 printf(" ");
32             res=a[i];
33             x--;
34             if (!x)
35                 break;
36         }
37     printf("
");
38 }
39  
40 int find(int x)
41 {
42     int l=1,r=ans,tmp=0;
43     while (l<=r)
44     {
45         int m=(l+r)>>1;
46         if (b[m]>x)
47             tmp=m,l=m+1;
48         else
49             r=m-1;
50     }
51     return tmp;
52 }
53  
54 void get()
55 {
56     for (int i=n;i;i--)
57     {
58         int t=find(a[i]);
59         f[i]=t+1;
60         ans=max(ans,t+1);
61         //b[t+1]=min(b[t+1],a[i]);
62         if(b[t+1]<a[i])
63             b[t+1]=a[i];
64     }
65 }
66  
67 int main()
68 {
69     scanf("%d",&n);
70     for (int i=1;i<=n;i++)
71         scanf("%d",&a[i]);
72     get();
73     scanf("%d",&m);
74     while (m--)
75     {
76         scanf("%d",&x);
77         if (x<=ans)
78             work(x);
79         else
80             printf("Impossible
");
81     }   
82     return 0;
83 }
原文地址:https://www.cnblogs.com/yangjiyuan/p/5343113.html