CF1730F Almost Sorted 题解
Un1quAIoid · · 个人记录
传送门: F. Almost Sorted
题目大意:
给定长度为
看到
考虑从
然而常数还是太大了,必须考虑继续优化。
注意到
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 5005;
const int Mod = 998244353;
int n, K, p[MAXN], id[MAXN];
int f[MAXN][1 << 8];//f[i][S] 表示未填的数中最小的是 i,(i,i+k] 填的情况为 S 时的最小逆序对数
inline void chkMin(int &a, int b) { if (a > b) a = b; }
int tot, rt[MAXN];
struct node {
int ls, rs, sum;
} T[MAXN * 15];
void upd(int &p, int vp, int l, int r, int gk) {
T[p = ++tot] = T[vp];
T[p].sum++;
if (l == r) return;
int mid = (l + r) >> 1;
if (mid >= gk) upd(T[p].ls, T[vp].ls, l, mid, gk);
else upd(T[p].rs, T[vp].rs, mid + 1, r, gk);
}
int query(int p, int l, int r, int gl, int gr) {
if (gl > gr) return 0;
if (l >= gl && r <= gr || !p) return T[p].sum;
int mid = (l + r) >> 1, ret = 0;
if (mid >= gl) ret = query(T[p].ls, l, mid, gl, gr);
if (mid < gr) ret += query(T[p].rs, mid + 1, r, gl, gr);
return ret;
}
int main() {
scanf("%d%d", &n, &K);
for (int i = 1; i <= n; i++) {
scanf("%d", &p[i]);
id[p[i]] = i;
upd(rt[i], rt[i - 1], 1, n, p[i]);
}
memset(f, 0x3f, sizeof(f));
f[1][0] = 0;
for (int i = 1; i <= n; i++)
for (int S = 0; S < 1 << K; S++) if (f[i][S] < 1e9) {
int mn = min(K + 1, n + 1 - i);
for (int j = min(K, n - i); j; j--) if (!(S >> j - 1 & 1)) {
mn = j;
int cnt = (id[i] < id[i + j]) + query(rt[id[i + j]], 1, n, i + K + 1, n);
for (int k = min(K, n - i); k; k--) if (!(S >> k - 1 & 1))
cnt += (id[i + k] < id[i + j]);
chkMin(f[i][S | 1 << j - 1], f[i][S] + cnt);
}
int cnt = query(rt[id[i]], 1, n, i + K + 1, n);
for (int j = min(K, n - i); j; j--) if (!(S >> j - 1 & 1))
cnt += (id[i + j] < id[i]);
chkMin(f[i + mn][S >> mn], f[i][S] + cnt);
}
printf("%d", f[n + 1][0]);
return 0;
}