nlogn求出最长上升子序列长度。
对每次询问,贪心地回答。设输入为x。当前数a[i]可能成为答案序列中的第k个,则若 f[i]>=x-k && a[i]>ans[k-1] 即可。
f[i]表示以a[i]开头的最长上升子序列长度。
但这个东西难以统计。so 我们将原序列反序,求f[i] 表示以 a[i]为结尾的最长下降子序列长度即可。最后再将f、a reverse一下。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 int a[10001],n,m,en=1,len,last; 5 int b[10001];//b[i]:将a翻转后,长度为i的最长下降子序列的末尾 6 int c[10001];//c[i]:将a翻转后,以a[i]开头的最长下降子序列的长度 7 bool cmp(const int &a,const int &b){return a>b;} 8 int main() 9 { 10 scanf("%d",&n); 11 for(int i=1;i<=n;i++) scanf("%d",&a[n-i+1]); 12 scanf("%d",&m); 13 b[1]=a[1]; c[1]=1; 14 for(int i=2;i<=n;i++) 15 { 16 int *p=lower_bound(b+1,b+en+1,a[i],cmp); 17 if(!(*p)) ++en; 18 *p=a[i]; 19 c[i]=p-b; 20 } 21 for(int i=1;i<=(n>>1);i++) swap(c[i],c[n-i+1]),swap(a[i],a[n-i+1]); 22 for(int i=1;i<=m;i++) 23 { 24 scanf("%d",&len); 25 if(len>en) 26 { 27 puts("Impossible"); 28 continue; 29 } last=0; 30 for(int j=1;j<=n;++j) 31 if(c[j]>=len&&a[j]>last) 32 { 33 printf("%d",last=a[j]); 34 if(!(--len)) 35 { 36 puts(""); 37 break; 38 } putchar(' '); 39 } 40 } 41 return 0; 42 }