P4870 [BalticOI 2009] 甲虫 (Day1) 分析
题目概述
有 \(n\) 个位置有 \(m\) 个水滴,你在 \(0\) 的位置,每过一个单位,有水滴的地方个数都少 \(1\)。
其中:\(1\leq n\leq 300,-10^9\leq x_i\leq 10^9\)。
分析
感觉很典。
首先先对 \(x\)(带上 \(0\))排序。
我们考虑区间 \(dp\)。
设 \(f_{i,j}\) 表示最小化 \([i,j]\) 的位置上所有的水滴的丢失。
我们假设 \(len\) 表示总长度,\(j - i + 1\) 表示的是我这段区间水全部喝完的长度。
我们发现我们不能确定它是在最左边还是最右边,添加 \(0/1\) 来表示即可。
随便举个例子(其他情况同理):假如向左边扩展且一开始在最左边。
那么显然:
\[f_{i,j,0}=f_{i+1,j,0}+(len-(r-l+1-1))\times(x_{i+1}-x_i)
\]
为什么?因为距离乘上还有多少位置的水滴没有喝。
代码
时间复杂度 \(\mathcal{O}(n^3)\)。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#define int long long
#define N 305
using namespace std;
int n,m,x[N],f[N][N][2];
signed main(){
cin >> n >> m;
for (int i = 1;i <= n;i ++) scanf("%lld",&x[i]);
x[++n] = 0;
stable_sort(x + 1,x + 1 + n);
int pos = lower_bound(x + 1,x + 1 + n,0) - x,ans = 0;
for (int len = 1;len <= n;len ++) {
memset(f,0x7f,sizeof f);
f[pos][pos][0] = 0,f[pos][pos][1] = 0;
for (int length = 2;length <= len;length ++)
for (int i = 1;i + length - 1 <= n;i ++) {
int j = i + length - 1;
f[i][j][0] = min(f[i][j][0],f[i + 1][j][0] + (len - (j - i)) * (x[i + 1] - x[i]));
f[i][j][0] = min(f[i][j][0],f[i + 1][j][1] + (len - (j - i)) * (x[j] - x[i]));
f[i][j][1] = min(f[i][j][1],f[i][j - 1][1] + (len - (j - i)) * (x[j] - x[j - 1]));
f[i][j][1] = min(f[i][j][1],f[i][j - 1][0] + (len - (j - i)) * (x[j] - x[i]));
ans = max(ans,m * (j - i) - f[i][j][0]);
ans = max(ans,m * (j - i) - f[i][j][1]);
}
}
cout << ans;
return 0;
}

浙公网安备 33010602011771号