bzoj1046: [HAOI2007]上升序列
首先是O(nlogn) 的最长上升子序列,我居然一直不会。。。。(雾)。
用一个maxv[i] 数组表示长度为i的上升子序列的第一个数的最大值,这样就可以二分求当前上升子序列的长度了。
注意这道题字典序最小是指下标。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 10000 + 10; const int INF = 0x3f3f3f3f; int a[maxn],maxv[maxn],f[maxn],res[maxn]; int n,m,maxlen; void input() { scanf("%d",&n); for(int i = 1; i <= n; i++) scanf("%d",&a[i]); } void build() { for(int i = 1; i <= n; i++) maxv[i] = -INF; maxv[0] = INF; maxv[1] = a[n]; f[n] = 1; maxlen = 1; for(int i = n-1,cur,l,r,mid; i >= 1; i--) { l = 0; r = maxlen+1; cur = 0; while(l <= r) { mid = (l+r) >> 1; if(a[i] < maxv[mid]) l=cur= mid + 1; else r = mid - 1; } maxlen = max(maxlen,f[i] = cur); maxv[cur] = max(maxv[cur],a[i]); } } void solve() { scanf("%d",&m); while(m--) { int len,cnt; scanf("%d",&len); if(len > maxlen) { printf("Impossible\n"); continue; } res[cnt=0] = -INF; for(int i = 1; i <=n && cnt < len; i++) if(f[i] >= len-cnt && a[i] > res[cnt]) res[++cnt] = a[i]; for(int i = 1; i < cnt; i++) printf("%d ",res[i]); printf("%d\n",res[cnt]); } } int main() { input(); build(); solve(); return 0; }