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 }
没有人能阻止我前进的步伐,除了我自己!