[bzoj1046][HAOI2007]上升序列

一个有意思的题。
很显然,这是LIS问题的加强版。
对于每一个询问,我们从前到后检查每一个元素,如果f[i]>=x那么输出,然后x--。如果x最终为零,那么说明有解。
证明:
首先,由于我们是从前考虑的每一个元素,所以保证了字典序最小。
其次,因为如果对于一个元素i|f[i]>x,那么从i后面一定至少能够找到x个元素使得构成一个长度为x的序列。
考虑到字典序的定义,这样贪心一定是最优的。
我们处理LIS时,令g[i]为使f[j]==i的最大j,这样可以用二分查照优化转移,复杂度从O(n2)降到了O(nlogn)
当然,这个题目不优化,直接使用O(n2)的算法也完全可以卡过。
下面上代码。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10001;
struct num {
    int value, pos;
    bool operator < (const num& b) const {
        return this->pos<b.pos;
    }
} a[maxn];
int n, m, Ma;
int f[maxn];
void getlis() {
    f[n-1] = 1;
    for(int i = n-2; i >= 0; i--) {
        int ans = 0;
        for(int j = i+1; j < n; j++) {
            if(a[j].value>a[i].value && f[j] > ans){ 
                ans = f[j];
            }
        }
        f[i] = ans+1;
    }
}
void getlis2() {
    f[n-1] = 1;
    int g[maxn]; //define g[i] to be the max j that let f[j] = i
    memset(g, -1, sizeof(g));
    g[0] = 0x3f3f3f;
    for(int i = n - 1; i >= 0; i--) {
        int ans = 0;
        int L = 0;
        int R = n;
        while(L < R) {
            if(R-L <= 1) break;  //二分查找最小的比x大的元素
            int mid = (L+R)/2;
            if(g[mid] > a[i].value) L = mid;
            else R = mid;
        }
        ans = L;
        f[i] = ans+1;
        g[ans+1] = max(g[ans+1], a[i].value);
    }
}
void solve() {
    sort(a, a+n);
    scanf("%d", &m);
    while(m--) {
        int l;
        scanf("%d", &l);
        int x = l;
        int cnt = 0;
        int b[maxn];
        int lastpos = 0;
        for(int i = 0; i < n; i++) {
            if(f[a[i].pos] >= x && a[i].value> lastpos) {
                b[cnt++] =  a[i].value;
                x--;
                lastpos = a[i].value;
            }
        }
        if(cnt < l-1) printf("%s\n", "Impossible");
        else {
           for(int i = 0; i < l; i++) {
              printf("%d", b[i]);
              if(i!=l-1) putchar(' '); 
             } 
           printf("\n");
        }
    }
}
int main() {
    scanf("%d", &n);
    for(int i = 0; i < n; i++) {
        int x;
        scanf("%d", &x);
        a[i] = {x, i};
        Ma = max(Ma, x);
    }
    getlis2();
//    for(int i = 0; i < n; i++) cout << f[i] << ' ';
solve();
}

posted on 2017-01-20 16:54  蒟蒻konjac  阅读(181)  评论(0编辑  收藏  举报