版权声明:博主写博客也挺不容易,转载当然阔以,记得先吱一声~ https://blog.csdn.net/Cold_Chair/article/details/86499908
Description:
题解:
非常容易想到一个 的dp,于是做不动了。
考虑一个数变大,这个序列的答案只会更大,所以答案不会超过
因此状态互换。
设 表示从i开始,在花费j的代价最远能走到哪里。
枚举一个点p:
发现瓶颈在a[p],不妨对a[p]相同的一起做,维护前缀max,p在j的前面虽然意义上不合法,但是答案只会更劣,所以不用担心答案会错,这是一个简单的套路。
转移复杂度 ,维护前缀max复杂度 ,卡卡常数就能过。
实际上有更优的复杂度:
再设
表示从i开始,代价为j,最左能够到哪儿。
这两个东西可以互相转移,也是用维护前后缀max的方式,比较巧妙。
#include<cstdio>
#include<cstring>
#define pp printf
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
using namespace std;
const int N = 1e5 + 5;
int n, a[N], f[154][N], mx[N];
char s[N];
int main() {
freopen("cost.in", "r", stdin);
freopen("cost.out", "w", stdout);
scanf("%s", s + 1); n = strlen(s + 1);
fo(i, 1, n) a[i] = s[i] - '0';
fo(i, 1, n) f[a[i]][i] = i, f[0][i] = i - 1;
fo(j, 0, 153) f[j][n + 1] = n;
fo(j, 1, 153) {
fo(i, 1, n) f[j][i] = max(f[j][i], f[j - 1][i]);
fo(k, 1, 9) {
if(j < k) break;
fo(i, 1, n) if(a[i] == k)
mx[i] = max(mx[i - 1], f[j - a[i]][i + 1]); else
mx[i] = mx[i - 1];
fo(i, 1, n) mx[i] = max(mx[i], mx[i - 1]);
fo(i, 1, n) f[j][i] = max(f[j][i], mx[f[j - k][i] + 1]);
}
if(f[j][1] >= n) {
printf("%d\n", j); return 0;
}
}
}