题意:
一个整数序列,每次操作可以对其中一个数加1或者减1。
求把这个序列变成非减序列所需的最少操作次数。
思路:
设原序列是A,目标序列是B
那么容易知道,B中的元素一定是A中元素的子集。
尝试用
f[i][j]
来表示,将前i个数变成非减序列,且最后一个元素的高度为
a[j],1<=j<=i
的最少操作
但是很快发现这个方程是错误的,因为j的取值范围应该是A中所有元素。
正确的方式是,将A中元素排序得到C
f[i][j]
表示 将前i个变成非减,最后元素不大于
c[j]
的最少操作
f[i][j]=min(f[i][j−1],f[i−1][j]+abs(a[i]−c[j]))
// 空间优化至一维
LL solve() {
rep(i, 1, n) b[i] = a[i];
sort(b+1, b+1+n);
int len = unique(b+1, b+1+n) - b-1;
// 边界处理
f[1] = abs (b[1] - a[1]);
rep(i, 2, len) f[i] = min (f[i-1], abs(b[i]-a[1]));
rep(i, 2, n) {
f[1] = f[1] + abs(a[i] - b[1]);
rep(j, 2, len) {
f[j] = min (f[j-1], f[j] + abs (a[i] - b[j]));
}
}
LL ans = f[1];
rep(i, 1, len) ans = min (ans, f[i]);
return ans;
}