bzoj1046
LIS+贪心
因为是要字典序尽量的小,但是如果我们从头做,就无法判断选了这个是否能够>=l,那么我们倒着跑一遍LDS,然后每次从尾部贪心,如果这个能选就选,判断标准是cnt+dp[i]>=l,就是已经选的加上这个的LDS比L大就是可以选。
#include<bits/stdc++.h> using namespace std; const int N = 10010; int n, m; int dp[N], tree[10000010], last[N], a[N]; int query(int l, int r, int x, int a, int b) { if(l > b || r < a) return 0; if(l >= a && r <= b) return tree[x]; int mid = (l + r) >> 1, i = query(l, mid, x << 1, a, b), j = query(mid + 1, r, x << 1 | 1, a, b); if(dp[i] > dp[j]) return i; else if(dp[i] < dp[j]) return j; else return i > j ? i : j; } void update(int l, int r, int x, int pos, int i) { if(l == r) { if(dp[i] > dp[tree[x]] || (dp[i] == tree[x] && i > tree[x])) tree[x] = i; return; } int mid = (l + r) >> 1; if(pos <= mid) update(l, mid, x << 1, pos, i); else update(mid + 1, r, x << 1 | 1, pos, i); if(dp[tree[x << 1]] > dp[tree[x << 1 | 1]]) tree[x] = tree[x << 1]; else if(dp[tree[x << 1 | 1]] > dp[tree[x << 1]])tree[x] = tree[x << 1 | 1]; else tree[x] = tree[x << 1] > tree[x << 1 | 1] ? tree[x << 1] : tree[x << 1 | 1]; } int main() { // freopen("lis.in", "r", stdin); // freopen("lis.out", "w", stdout); scanf("%d", &n); int m = 0; for(int i = 1; i <= n; ++i) { scanf("%d", &a[i]); m = max(m, a[i]); } reverse(a + 1, a + n + 1); for(int i = 1; i <= n; ++i) { int j = query(1, m, 1, a[i] + 1, m); dp[i] = dp[j] + 1; update(1, m, 1, a[i], i); last[i] = j; } scanf("%d", &m); while(m--) { int l, val = 0, cnt = 0; scanf("%d", &l); vector<int> ans; for(int i = n; i && cnt < l; --i) if(dp[i] + cnt >= l && val < a[i]) { val = a[i]; ++cnt; ans.push_back(a[i]); } if(cnt == 0) puts("Impossible"); else { for(int i = 0; i < ans.size() - 1; ++i) printf("%d ", ans[i]); printf("%d\n", ans[ans.size() - 1]); } } // fclose(stdin); // fclose(stdout); return 0; }