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 }

 

 

 

你可能感兴趣的:(2007)