CodeForces 1730F Almost Sorted
过程相当于是将 \(p\) 重排列。设 \(b_i\) 为 \(p\) 中数为 \(i\) 的位置。考虑当前填的数 \(x\) 贡献的逆序对数,相当于是当前所有已经填入 \(p\) 的数 \(y\),都有 \([b_y > b_x]\) 的贡献。
考虑 \(p_{q_i} \le p_{q_j} + k\) 意味着什么。
当正在填 \(p_{q_i}\) 时,之后还没填的数 \(\ge p_{q_i} - k\);当正在填 \(p_{q_j}\) 时,之前填了的数 \(\le p_{q_j} + k\)。
综合一下就是,若考虑某个前缀已经填入 \(p\) 的状态,最小的还没填的数 \(\le\) 最大的已经填了的数 \(+ k\)。
由此可以想到状压。设 \(f_{i, S}\) 为当前最小的还没填的数为 \(i + 1\),\([i + 1, i + k + 1]\) 的数的填入状态为 \(S\)(填入为 \(1\),没填入为 \(0\))。
转移枚举当前位填 \(x\)(\(x\) 只能在 \([i + 1, i + k + 1]\) 中),分开计算 \([1, i]\) 的贡献和 \([i + 1, i + k + 1]\) 的贡献即可。前部分预处理一个前缀有多少个 \(b_i \ge j\),后部分暴力。然后还要计算,填了 \(x\) 后,新的最小的没填的数是多少。
时间复杂度 \(O(n^2 + n k^2 2^k)\)。
压行后是 CF 最短解。
code
// Problem: F. Almost Sorted
// Contest: Codeforces - Codeforces Round 823 (Div. 2)
// URL: https://codeforces.com/problemset/problem/1730/F
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 5050;
const int maxm = (1 << 9) + 9;
int n, m, a[maxn], b[maxn], f[maxn][maxm], c[maxn][maxn];
void solve() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
b[a[i]] = i;
}
mems(f, 0x3f);
f[0][0] = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
c[i][j] = c[i - 1][j] + (j <= b[i]);
}
}
for (int i = 0; i < n; ++i) {
for (int S = 0; S < (1 << (m + 1)); ++S) {
for (int j = 0; j <= m; ++j) {
if (S & (1 << j)) {
continue;
}
int t = c[i][b[i + j + 1]];
for (int k = 0; k <= m; ++k) {
if (S & (1 << k)) {
t += (b[i + k + 1] > b[i + j + 1]);
}
}
int T = S | (1 << j), k = 0;
while (k <= m && (T & (1 << k))) {
++k;
}
T >>= k;
f[i + k][T] = min(f[i + k][T], f[i][S] + t);
}
}
}
printf("%d\n", f[n][0]);
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}