[bzoj1046][HAOI2007]上升序列

分類:技術 時間:2017-01-20

一個有意思的題。
很顯然,這是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();
}




Tags: 動態規劃 字典序 貪心

文章來源:


ads
ads

相關文章
ads

相關文章

ad