首页 > 技术文章 > [HAOI2007]上升序列

dummyummy 2018-10-15 09:48 原文

BZOJ/洛谷
刚开始时间复杂度估错了,只好看题解。\(O(n^2)\)的做法还写崩了,难受。
坑点:是下标字典序最小,不是字典序最小!
最原始的\(O(nlogn)\)做法中的\(f[i]\)表示的是以\(i\)结尾的\(LIS\)的最大长度,本题我们为了方便,倒着求最长下降子序列,于是\(f[i]\)表示的是以\(i\)开头的最长上升子序列长度。然后我们\(O(nlogn)\)地求出\(f\)数组。输出时就遍历一遍,复杂度\(O(nm)\)
AC代码:

#include <cstdio>
#define N 100000
#define re register
int n, m, maxl, a[N+5], f[N+5], best[N+5], ans[N+5];
namespace mine {
    inline char Getchar() {
        static char buf[2048],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,2048,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read() {
        int s = 0; re char c = Getchar();
        while(c < '0' || c > '9') c = Getchar();
        while(c >= '0' && c <= '9') s = s*10+c-'0',c = Getchar();
        return s;
    }
    template <typename T> T max(T _x, T _y){ return _x>_y?_x:_y; }
    template <typename T> T min(T _x, T _y){ return _x<_y?_x:_y; }
}
using namespace std;
using namespace mine;
int find(int x) {
    int l = 1, r = maxl, mid, ret = 0;
    while(l <= r) {
        mid = (l+r)/2;
        if(best[mid] > x) l = mid+1, ret = mid;
        else r = mid-1;
    }
    return ret;
}
void dp() {
    for(int i = n, t; i >= 1; --i) {
    	t = find(a[i]);
    	maxl = max(maxl, t+1);
    	f[i] = t+1;
    	if(best[t+1] < a[i]) best[t+1] = a[i]; 
    }
}
void print(int x) {
    int last = 0;
    for(int i = 1; i <= n; ++i) {
        if(f[i] >= x && a[i] > last) {
            printf("%d ", a[i]);
            last = a[i];
            x--;
            if(!x) break;
        }
    }
    printf("\n");
}
int main() {
    n = read();
    for(re int i = 1; i <= n; ++i) a[i] = read();
    dp(); m = read();
    for(int i = 1, t; i <= m; ++i) {
        t = read();
        if(t > maxl) puts("Impossible");
        else print(t);
    }
    return 0;
}

推荐阅读