[UESTC 594] 我要长高
Posted kma093
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[UESTC 594] 我要长高相关的知识,希望对你有一定的参考价值。
题目链接:
题目分析:
设\(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\
\beginaligned
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)\\endaligned
\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;
以上是关于[UESTC 594] 我要长高的主要内容,如果未能解决你的问题,请参考以下文章