题面
解法
- 结论应该比较显然,就是相当于找字典序第 大的 。
- 考虑怎么证明其正确性。对于一次 操作,可以发现除 之外的元素的相对位置并不发生改变。那么,现在相当于要找一个最大的集合 ,使得它们在序列中严格递增。显然 等于 的长度。然后再考虑字典序的问题。最后答案的集合 为 的补集,那么求字典序第 小的集合 就相当于求字典序第 大的集合 。
- 那么问题就是怎么求最后的 。
- 考虑到字典序应该是从第一位开始按位确定的,所以我们可以设 表示以 开头的 的长度, 表示以 开头的 的个数。
- 转移比较简单,用树状数组即可。
- 然后不妨将 相同的全部放进一个vector里,那么显然的是,在同一个vector中有两个数 满足 ,那么 ,否则 一定会更新。那么说明在编号 有序的情况下 也同样有序。
- 然后直接按位确定即可。
- 时间复杂度:
【注意事项】
- 一开始的思路有些问题,认为倒着确定也同样满足字典序的条件。其实这个显然是错误的,这个结论只能满足于 的情况。
- 注意 最大只有 ,但是 很有可能会超过 ,所以在求 的时候要与 取最小值,否则会变成负数出现问题。(因为这个问题调了好久)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
template <typename T> void chkmax(T &x, T y) {x = x > y ? x : y;}
template <typename T> void chkmin(T &x, T y) {x = x > y ? y : x;}
template <typename T> void read(T &x) {
x = 0; int f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
const int N = 100010; const ll inf = 1e18l;
int n, a[N], st[N], used[N]; ll K;
vector <ll> v[N], cnt[N];
struct BIT {
ll f[N];
void modify(int x, ll v) {for (; x <= n; x += x & -x) f[x] = min(f[x] + v, inf);}
void Clear(int x) {for (; x <= n; x += x & -x) f[x] = 0;}
ll query(int x) {
ll ret = 0;
for (; x; x -= x & -x) ret = min(inf, ret + f[x]);
return ret;
}
} T;
int main() {
read(n), read(K);
for (int i = 1; i <= n; i++) read(a[i]);
int len = 0;
for (int i = n; i; i--) {
int l = 1, r = len, ans = 0;
while (l <= r) {
int mid = (l + r) >> 1;
if (st[mid] < a[i]) l = mid + 1, ans = mid;
else r = mid - 1;
}
v[ans + 1].push_back(i);
if (ans == len) st[++len] = a[i];
else st[ans + 1] = a[i];
}
for (int i = 0; i < v[1].size(); i++) cnt[1].push_back(1);
for (int i = 2; i <= len; i++) {
int p = 0;
for (int j = 0; j < v[i].size(); j++) {
int k = v[i][j];
while (p < v[i - 1].size() && v[i - 1][p] > k)
T.modify(n - a[v[i - 1][p]] + 1, cnt[i - 1][p]), p++;
cnt[i].push_back(T.query(n - a[k] + 1));
}
for (int j = 0; j < v[i - 1].size(); j++) T.Clear(n - a[v[i - 1][j]] + 1);
}
cout << n - len << "\n";
for (int i = len, x = 0; i; i--)
for (int j = 0; j < v[i].size(); j++) {
int k = v[i][j];
if (k < x || a[k] < a[x]) continue;
if (cnt[i][j] < K) {K -= cnt[i][j]; continue;}
used[a[k]] = 1, x = k; break;
}
for (int i = 1; i <= n; i++) if (!used[i]) cout << i << "\n";
return 0;
}