题解:CF2159D2 Inverse Minimum Partition (Hard Version)

· · 题解

我是小菜鸡 Div.2 rk60+

通过模拟我们可以发现一下几个性质。

我们设 a 的值域为 V

  1. 任意 f[l, r] 不大于 2\log(V)≤128
  2. 总有一个最优解,只使用成本最多为 3 的子数组

定义 g_{i, r} 表示,以 r 为右端点,使用 1 次成本为 i 的子数组能到达的最左边的位置,由于性质3,1≤i≤3,可以使用线段树或者 RMQ + 二分求出 g 数组。

dp_{i, r} 表示右端点为 r 的时候,代价 f[l,r] ≤ i 的最小 l,由于性质 2i \leq 128,我们有转移。

根据性质 1 的单调性我们可以知道,最终答案

## code ```cpp #include <cstring> #include <algorithm> #include <cstdio> #include <vector> using namespace std; #define ll long long const int N = 400005; const int mod = 1000000007; const int INF = 0x3f3f3f3f; int T, n; ll a[N], mn[N][20]; int lg[N], st[4][N][20], f[130]; int st_query(int k, int l, int r) { int len = lg[r - l + 1]; return min(st[k][l][len], st[k][r - (1 << len) + 1][len]); } ll get(int l, int r) { int len = lg[r - l + 1]; return min(mn[l][len], mn[r - (1 << len) + 1][len]); } int binary(int R, ll x) { // 1 ~ r 范围内使得 min[i ~ r] >= x 大最小的i int l = 1, r = R; while (l <= r) { int mid = (l + r) >> 1; if (get(mid, R) < x) l = mid + 1; else r = mid - 1; } return l; } int main() { for (int i = 2; i < N; i++) lg[i] = lg[i >> 1] + 1; int T; scanf("%d", &T); while (T--) { scanf("%d", &n); int t = 0; for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); } for (int i = 1; i <= n; i++) mn[i][0] = a[i]; for (int i = 1; (1 << i) <= n; i++) { for (int j = 1; j + (1 << i) - 1 <= n; j++) { mn[j][i] = min(mn[j][i - 1], mn[j + (1 << (i - 1))][i - 1]); } } // get the array of L for (int r = 1; r <= n; r++) { for (int i = 1; i <= 3; i++) { st[i][r][0] = binary(r, (a[r] + i - 1) / i); } } for (int k = 1; k <= 3; k++) { for (int i = 1; (1 << i) <= n; i++) { for (int j = 1; j + (1 << i) - 1 <= n; j++) { st[k][j][i] = min(st[k][j][i - 1], st[k][j + (1 << (i - 1))][i - 1]); } } } ll ans = 0; for (int r = 1; r <= n; r++) { f[0] = r + 1; for (int i = 1; i <= 128; i++) { f[i] = INF; for (int k = 1; k <= min(i, 3); k++) { f[i] = min(st_query(k, max(f[i - k] - 1, 1), r), f[i]); } } for (int i = 1; i <= 128; i++) { ans += (f[i - 1] - f[i]) * i; } } printf("%lld\n", ans); } return 0; } ```