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;
}
posted @ 2016-04-10 21:18  invoid  阅读(161)  评论(0编辑  收藏  举报