把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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;
}
posted @ 2025-10-13 11:05  high_skyy  阅读(3)  评论(0)    收藏  举报
浏览器标题切换
浏览器标题切换end