【思路要点】
- 显然有 O ( N 2 ) O(N^2) O(N2) 的以决策单调性优化区间 d p dp dp 的做法。
- 考虑本题的特殊性,数的权值都很小,答案不会超过 9 ∗ L o g 2 N 9*Log_2N 9∗Log2N 。
- 这意味着我们可以考虑将答案计入状态。
- 注意到在区间 d p dp dp 的做法中我们可以得出性质 c o s t i , j ≥ c o s t i + 1 , j + c o s t i , j − 1 cost_{i,j}≥cost_{i+1,j}+cost_{i,j-1} costi,j≥costi+1,j+costi,j−1 。记 d p i , j dp_{i,j} dpi,j 表示以 i i i 为后缀的区间,代价不超过 j j j 的情况下,最靠左的左端点可以是多少。
- 转移时枚举当前区间选择的分段点的权值即可。
- 时间复杂度 O ( 9 2 ∗ N L o g N ) O(9^2*NLogN) O(92∗NLogN) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 5; const int MAXM = 188; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } char s[MAXN]; int n, m, a[MAXN]; int nxt[MAXN][10], dp[MAXN][MAXM]; int main() { freopen("cost.in", "r", stdin); freopen("cost.out", "w", stdout); scanf("%s", s + 1); n = strlen(s + 1); for (int i = 1; i <= n; i++) a[i] = s[i] - '0'; for (int i = 1; i <= 9; i++) nxt[n + 1][i] = n + 1; for (int i = n; i >= 1; i--) { for (int j = 1; j <= 9; j++) nxt[i][j] = nxt[i + 1][j]; nxt[i][a[i]] = i; } m = 180; for (int i = 1; i <= n; i++) for (int j = 0; j <= m; j++) { dp[i][j] = i + 1; for (int k = 1; k <= 9 && k <= j; k++) { int from = dp[i][j - k] - 1; if (from == 0) dp[i][j] = 1; else { from = nxt[from][k]; if (from > i) continue; if (from == 1) dp[i][j] = 1; else chkmin(dp[i][j], dp[from - 1][j - k]); } } } int ans = 1; while (dp[n][ans] > 1) ans++; writeln(ans); return 0; }