题解 P4870 【[BalticOI 2009 Day1]甲虫】
题意
甲虫在坐标轴0位置,左右移动使得喝到的水最多,同时一单位时间甲虫可以移动一个单位距离,一单位时间每滴水分蒸发1单位体积
思路
考场上没有看懂题目,把水滴的体积和单位距离搞混了
这道题是一道很好的\(dp\)题目,其关键在于怎么定义
按照一般的定义,\(dp_{[l][r][0/1]}\)表示已经喝了\(l\)到\(r\)区间的水之后,在\(l\)或\(r\)位置,喝到的水的最大值,但是对于不同的值而言,经过的时间不一样,无法算出下一次转移时新水滴的贡献,换句话说,就是不同的值对应的经过的时间不同,值最大的不一定是最优的,如果维护了时间和喝的总水滴体积,把每种状态全部存下来,并不好处理,时间复杂度很差,考虑换种定义状态
在枚举一个\(len\)(表示要喝\(len\)滴水)的前提下,定义\(dp_{[l][r][0/1]}\)表示已经喝了\(l\)到\(r\)区间内所有的水滴,所浪费的水体积最小值,所谓浪费的水体积也就是蒸发掉的水体积数,其中包括了还没有喝的\((len - (r - l + 1))\)滴水和已经喝掉的\((r - l + 1)\)滴水的总浪费。
此时浪费的水滴数很好算,知道了还没有喝的水滴数和这次需要移动的长度(即话费的时间),这次转移多浪费的水滴体积就是\((len - (r - l + 1) - 1)\) \(\times\) $\bigtriangleup x $
转移方程:
定义\(len\)表示这次要喝\(len\)滴水,\(siz = (r - l + 1)\)
\(dp_{[i][j][0]}\) = \(min(dp_{[l + 1][r][0]} + (len - siz + 1) * (x[l + 1] - x[l]), dp_{[l + 1][r][1]} + (len - siz + 1) * (x[r] - x[l]))\)
\(dp_{[i][j][1]}\) = \(min(dp_{[l][r - 1][1]} + (len - siz + 1) * (x[r] - x[r - 1]), dp_{[l][r - 1][0]} + (len - siz + 1) * (x[r] - x[l]))\)
\(Code\)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
inline int read () {
int x = 0, f = 1; char ch = getchar();
for (;!isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
return x * f;
}
const int maxn = 405;
int n, m;
long long dp[maxn][maxn][2];
long long ans;
int x[maxn];
int main () {
freopen ("beetle.in", "r", stdin);
freopen ("beetle.out", "w", stdout);
n = read(), m = read();
int flag = 0;
for (register int i = 1; i <= n; i++) {
x[i] = read();
}
x[++n] = 0;
sort (x + 1, x + 1 + n);
int pos = lower_bound(x + 1, x + 1 + n, 0) - x;
int r;
for (register int len = 1; len <= n; len++) {
memset (dp, 0x7f, sizeof dp);
dp[pos][pos][0] = 0, dp[pos][pos][1] = 0;
for (register int siz = 2; siz <= len; siz++) {
for (register int l = 1; l + siz - 1 <= n; l++) {
r = l + siz - 1;
dp[l][r][0] = min (dp[l + 1][r][0] + (len - siz + 1) * (x[l + 1] - x[l]), dp[l][r][0]);
dp[l][r][0] = min (dp[l + 1][r][1] + (len - siz + 1) * (x[r] - x[l]), dp[l][r][0]);
dp[l][r][1] = min (dp[l][r - 1][1] + (len - siz + 1) * (x[r] - x[r - 1]), dp[l][r][1]);
dp[l][r][1] = min (dp[l][r - 1][0] + (len - siz + 1) * (x[r] - x[l]), dp[l][r][1]);
ans = max (ans, m * (siz - 1) - dp[l][r][1]);
ans = max (ans, m * (siz - 1) - dp[l][r][0]);
}
}
}
cout<<ans<<endl;
return 0;
}