CF1437C 大厨莫诺卡普
1 CF1437C 大厨莫诺卡普
2 题目概要:
大厨莫诺卡普刚刚把 \(𝑛\) 个盘子放进烤箱里。 他知道\(𝑖\)菜的最佳烹饪时间为 \(𝑡_𝑖\) 分钟。
在任何正整数分钟 \(𝑇\) 莫诺卡普不能从烤箱中取出超过一个盘子。如果第 \(𝑖\) 道菜是在某一分钟的 \(𝑇\) 上放出来的,那么它的不愉快值就是 \(|𝑇−𝑡_𝑖|\),也就是 \(𝑇\) 和 \(𝑡_𝑖\) 之间差的绝对值。一旦盘子出了烤箱,它就不能再被放进去了。
莫诺卡普应该把所有的盘子都从烤箱里拿出来。莫诺卡普能获得的最小的总不愉快值是多少?
3 解题思路
分析性质,我们发现:取盘子一定是按照他们 \(t\) 的递增顺序来取的。这是因为,如果我们先取了 \(t\) 更大的盘子,那么该盘子产生的代价将比后取该盘子的代价要大。于是我们可以将给出的 \(t\) 递增排序。
由于我们要求出的值是最小代价,物体的维度是由时间构成的,我们便可以考虑如下状态。
\(dp[i][j]\) 表示在取了前 \(i\) 个盘子,第 \(i\) 个盘子取出时间为 \(j\) 的情况下的最小代价。
对于这个状态,我们发现它是由取 \(i-1\) 个盘子,第 \(i-1\) 个盘子取出时间为 \(1\)~\(j\) 的状态的最小值加上 \(\vert t_i - j\rvert\) 更新来的。转移方程便得出了:
\[dp[i][j] = min(dp[i][j], dp[i-1][k] + \lvert t_i - j \rvert)(k \in[1,j])
\]
注意:由于我们可以在大于 \(n\) 的时刻取出盘子,因此 \(j\) 可以最大可以取到 \(2*n\)。
4 代码实现
代码(空格警告):
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 205;
int n, maxn, T;
int a[N], dp[N][2*N];
int main()
{
cin >> T;
while (T--)
{
maxn = 0x3f3f3f3f;
memset(dp, 0x3f, sizeof(dp));
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
sort(a+1, a+n+1);
for (int i = 1; i <= 2*n; i++) dp[0][i] = 0;
for (int i = 1; i <= n; i++)
{
for (int j = i; j <= 2*n; j++)
{
if (j == 1) dp[i][j] = abs(1 - a[1]);
for (int k = 1; k < j; k++)
{
dp[i][j] = min(dp[i][j], dp[i-1][k] + abs(a[i] - j));
}
}
}
for (int i = 1; i <= 2*n; i++)
{
maxn = min(maxn, dp[n][i]);
}
cout << maxn << endl;
}
return 0;
}