BZOJ 1046 最长不降子序列(nlogn)

Posted on 2016-08-17 20:25  yyjxx2010xyu  阅读(124)  评论(0编辑  收藏  举报

nlogn的做法就是记录了在这之前每个长度的序列的最后一项的位置,这个位置是该长度下最后一个数最小的位置。显然能够达到最优。

BZOJ 1046中里要按照字典序输出序列,按照坐标的字典序,那么我萌可以把序列先倒着做最长下降子序列,然后我萌就可以知道以a[i]为开头的最长的长度了。每次扫一遍记录答案即可.

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <algorithm>
 5 using namespace std;
 6  
 7 inline void Get_Int(int &x)
 8 {
 9     char ch=getchar(); x=0;
10     while (ch<'0' || ch>'9') ch=getchar();
11     while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
12 }
13 const int Maxn=100100;
14 const int Inf=0x3f3f3f3f;
15 int n,m,a[Maxn],F[Maxn],Pos[Maxn],B[Maxn],top,Ans,x;
16 inline int Max(int x,int y) {return x>y?x:y;}
17 inline int Find(int x)
18 {
19     int l=1,r=n,Ret=0;
20     while (l<=r)
21     {
22         int mid=(l+r)>>1;
23         if (a[Pos[mid]]>x) Ret=mid,l=mid+1; else r=mid-1;
24     }
25     return Ret;
26 }
27 int main()
28 {
29     Get_Int(n);
30     for (int i=1;i<=n;i++) Get_Int(a[n-i+1]);
31     F[1]=1; Pos[1]=1; int Ans=1;
32     for (int i=2;i<=n;i++)
33     {
34         int t=Find(a[i]);
35         Pos[t+1]=i;
36         F[i]=t+1;
37         Ans=Max(t+1,Ans);
38     }
39      
40     Get_Int(m);
41     for (int i=1;i<=m;i++)
42     {
43         Get_Int(x); int top=0,Now=-Inf;
44         if (Ans<x) {puts("Impossible"); continue;} 
45         for (int i=n,j=x;i&&j;i--)
46             if (F[i]>=j && Now<a[i])
47             {
48                 Now=a[i];
49                 B[++top]=a[i];
50                 j--;
51             }
52         for (int i=1;i<x;i++) printf("%d ",B[i]); printf("%d\n",B[x]);
53     }
54     return 0;
55 }
C++