标签:stdin get define names git mem 身高 cpp hang
设\(dp[i][j]\)表示到第\(i\)个人,他的身高是\(j\)的时候的最小损失,然后得到一个朴素的转移方程
\(dp[i][j] = min(dp[i - 1][k] + abs(k - j) * C + (j - a[i]) ^ 2)\)
把无关的丢到\(min\)外面来
\[ dp[i][j] = \left\{
\begin{aligned}
min(dp[i - 1][k] + k * C) - j * C + (j - a[i]) ^ 2 (j < k) \min(dp[i - 1][k] - k * C) + j * C + (j - a[i]) ^ 2 (j > k)\\end{aligned}
\right.
\]
直接枚举\(i,j,k\)显然是\(O(n^3)\)的,看到有\(min / max\)考虑怎么单调队列一下
然后发现好像不用单调队列也可以,我们只需要存储当前\(min\)里面那一坨的最小值就可以了
#include<bits/stdc++.h>
#define INF (1000000000 + 7)
#define N (50000 + 10)
using namespace std;
inline int read() {
int cnt = 0, f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + c - '0'; c = getchar();}
return cnt * f;
}
int n, C, a[N], dp[N][105];
int gmin, lim, ans;
inline int Pow(int x) {return x * x;}
int main() {
// freopen("1.in", "r", stdin);
while (scanf("%d", &n) != EOF) {
C = read();
memset(dp, 0x3f3f, sizeof(dp));
for (register int i = 1; i <= n; ++i) a[i] = read(), lim = max(lim, a[i]);
for (register int i = a[1]; i <= lim; ++i) dp[1][i] = Pow(i - a[1]);
for (register int i = 2; i <= n; ++i) {
gmin = INF;
for (register int j = a[i - 1]; j <= lim; ++j) {
gmin = min(gmin, dp[i - 1][j] - C * j);
if (j >= a[i]) dp[i][j] = gmin + Pow(j - a[i]) + C * j;
}
gmin = INF;
for (register int j = lim; j >= a[i]; --j) {
gmin = min(gmin, dp[i - 1][j] + C * j);
if (j >= a[i]) dp[i][j] = min(dp[i][j], gmin + Pow(j - a[i]) - C * j);
}
}
ans = INF;
for (register int i = a[n]; i <= lim; ++i) ans = min(ans, dp[n][i]);
printf("%d\n", ans);
}
return 0;
}
标签:stdin get define names git mem 身高 cpp hang
原文地址:https://www.cnblogs.com/kma093/p/11508732.html