[关闭]
@ysner 2018-07-19T01:02:07.000000Z 字数 1216 阅读 2165

[HAOI2007]上升序列

贪心 LIS


题面

求一个长度为的序列长度为的字典序最小(最靠前)的上升序列。

解析

我好像忘了怎么求最长上升子序列

输出

从后往前枚举位置,枚到一个新数字时,二分出它在已有(它后面的)最长上升序列的合适位置,把它插在最小的、比它大的数的后面(因序列中数按后面的序列长度从小到大、倒着存在数组里)。
这样能快速求出每个点后面长度

  1. il int find(re int x)
  2. {
  3. re int l=1,r=len,ans=0;
  4. while(l<=r)
  5. {
  6. re int mid=l+r>>1;
  7. if(b[mid]>a[x]) ans=mid,l=mid+1;
  8. else r=mid-1;
  9. }
  10. return ans;
  11. }
  12. il void Pre()
  13. {
  14. fq(i,n,1)
  15. {
  16. f[i]=find(i)+1;
  17. b[f[i]]=a[i];
  18. len=max(len,f[i]);
  19. }
  20. }

算法

从前往后枚举的第几个数字,若且该数大于上一个,即无脑将该数加入序列。
由于从前往后,因而最优。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #define re register
  8. #define il inline
  9. #define ll long long
  10. #define max(a,b) ((a)>(b)?(a):(b))
  11. #define min(a,b) ((a)<(b)?(a):(b))
  12. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  13. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  14. using namespace std;
  15. const int N=1e4+100;
  16. int n,a[N],m,L,f[N],b[N],len;
  17. il ll gi()
  18. {
  19. re ll x=0,t=1;
  20. re char ch=getchar();
  21. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  22. if(ch=='-') t=-1,ch=getchar();
  23. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  24. return x*t;
  25. }
  26. int main()
  27. {
  28. n=gi();
  29. fp(i,1,n) a[i]=gi();
  30. Pre();
  31. m=gi();
  32. while(m--)
  33. {
  34. L=gi();
  35. if(L>len) {puts("Impossible");continue;}
  36. re int las=0;
  37. fp(i,1,n)
  38. if(f[i]>=L&&a[i]>a[las])
  39. {
  40. printf("%d ",a[i]);
  41. las=i;
  42. if(!(--L)) {puts("");break;}
  43. }
  44. }
  45. return 0;
  46. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注