题面
解法
- 结论应该比较显然,就是相当于找字典序第 K K K大的 L I S LIS LIS。
- 考虑怎么证明其正确性。对于一次 s o r t ( x ) sort(x) sort(x)操作,可以发现除 x x x之外的元素的相对位置并不发生改变。那么,现在相当于要找一个最大的集合 S S S,使得它们在序列中严格递增。显然 ∣ S ∣ |S| ∣S∣等于 L I S LIS LIS的长度。然后再考虑字典序的问题。最后答案的集合 S ′ S' S′为 S S S的补集,那么求字典序第 K K K小的集合 S ′ S' S′就相当于求字典序第 K K K大的集合 S S S。
- 那么问题就是怎么求最后的 S S S。
- 考虑到字典序应该是从第一位开始按位确定的,所以我们可以设 f [ i ] f[i] f[i]表示以 a [ i ] a[i] a[i]开头的 L I S LIS LIS的长度, s [ i ] s[i] s[i]表示以 a [ i ] a[i] a[i]开头的 L I S LIS LIS的个数。
- 转移比较简单,用树状数组即可。
- 然后不妨将 f [ i ] f[i] f[i]相同的全部放进一个vector里,那么显然的是,在同一个vector中有两个数 x , y x,y x,y满足 x > y x>y x>y,那么 a [ x ] < a [ y ] a[x]<a[y] a[x]<a[y],否则 f [ y ] f[y] f[y]一定会更新。那么说明在编号 x x x有序的情况下 a [ x ] a[x] a[x]也同样有序。
- 然后直接按位确定即可。
- 时间复杂度: O ( n log n ) O(n\log n) O(nlogn)
【注意事项】
- 一开始的思路有些问题,认为倒着确定也同样满足字典序的条件。其实这个显然是错误的,这个结论只能满足于 K = 1 K=1 K=1的情况。
- 注意 K K K最大只有 1 0 18 10^{18} 1018,但是 s [ i ] s[i] s[i]很有可能会超过 K K K,所以在求 s [ i ] s[i] s[i]的时候要与 1 0 18 10^{18} 1018取最小值,否则会变成负数出现问题。(因为这个问题调了好久)
代码
#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;
}