杭二中白马湖p1648邮局加强版

本文详细解析了杭二中白马湖竞赛题P1648的邮局选址问题加强版,探讨了动态规划(DP)和四边形不等式在解决此问题中的应用,帮助读者理解并掌握这类问题的解题思路和技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目题目链接

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N = 1600 + 10;

int s[N][N]; // 决策点 
LL w[N][N], f[N][N];
LL S[N];
int a[N];
int n, m;

// f[i][j] 表示前 i 个村庄建 j 个邮局最小花费 
// w[i][j] 表示第 i 个村庄和第 j 个村庄间建 1 个邮局的最少花费 
// s[i][j] 表示前 i 个村庄建 j 个邮局最小花费与建 j - 1 个邮局的决策点 
// a <= b <= c <= d
// w[a][b] + w[c][d] <= w[a][d] + w[b][c] 满足四边形不等式, 即满足决策点 s 单调
// 区间单调 : a <= b <= c <= d
// s[b][c] <= s[a][d]
// s[i][j - 1] <= s[i][j] <= s[i + 1][j] 

int main() {
    memset(f, 0x3f, sizeof(f));
    scanf("%d %d", &n, &m);
    if(m >= n) {
        printf("0");
        return 0;
    }
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    sort(a + 1, a + n + 1);
    for(int i = 1; i <= n; i++) S[i] = S[i - 1] + a[i];
    for(int i = 1; i <= n; i++) {
        for(int j = i; j <= n; j++) {
            // 计算 w
            int mid = (i + j) >> 1;
            w[i][j] = (mid - i) * a[mid] - (S[mid - 1] - S[i - 1]) + (S[j] - S[mid]) - (j - mid) * a[mid];
        }
    }
    for(int i = 1; i <= n; i++) s[i][1] = 1;
    for(int i = 1; i <= n; i++) f[i][1] = w[1][i];
    for(int j = 2; j <= m; j++) {
        s[n + 1][j] = n;
        // n -> 1 为了让 s[i + 1][j] 被求出来 
        for(int i = n; i >= j; i--) {
            for(int k = s[i][j - 1]; k <= s[i + 1][j]; k++) {
                if(f[i][j] > f[k][j - 1] + w[k + 1][i]) {
                    f[i][j] = f[k][j - 1] + w[k + 1][i];
                    s[i][j] = k;
                }
            }
        }
    }
    printf("%lld", f[n][m]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值