P4677 山区建小学题解

P4677 山区建小学

题目描述

政府在某山区修建了一条道路,恰好穿越总共 nnn 个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往。已知任意两个相邻的村庄之间的距离为 did_ididid_idi 为正整数),其中,0<i<n0<i<n0<i<n。为了提高山区的文化素质,政府又决定从 nnn 个村中选择 mmm 个村建小学。请根据给定的 nnnmmm 以及所有相邻村庄的距离,选择在哪些村庄建小学,才使得所有村到最近小学的距离总和最小,计算最小值。

输入格式

第一行为 nnnmmm,其间用空格间隔。

第二行为 n−1n-1n1 个整数,依次表示从一端到另一端的相邻村庄的距离,整数之间以空格间隔。

例如

10 3
2 4 6 5 2 4 3 1 3

表示在 101010 个村庄中建 333 所学校。第 111 个村庄与第 222 个村庄距离为 222,第 222 个村庄与第 333 个村庄距离为 444,第 333 个村庄与第 444 个村庄距离为 666,…,第 999 个村庄到第 101010 个村庄的距离为 333

输出格式

各村庄到最近学校的距离之和的最小值。

输入输出样例 #1

输入 #1

10 2
3 1 3 1 1 1 1 1 3

输出 #1

18

说明/提示

1≤m≤n<5001 \le m \le n < 5001mn<5001≤di≤1001 \le d_i \le 1001di100

思路

直接区间DP即可。

代码见下

#include<bits/stdc++.h> 
using namespace std;
long long n,m,a[100005],b[100005],b2[100005],b3[100005],f[505][505],db=0,op=1e18+7;
int main(){
	cin>>n>>m;
    for(int i=2;i<=n;i++){
        cin>>a[i];
        b[i]=b[i-1]+a[i];
    }
    memset(f,62,sizeof(f));
    for(int i=1;i<=n;i++){
        db=0;
        for(int j=1;j<=i;j++){
            db+=(b[i]-b[j]);
        }
        f[i][1]=db;
        for(int k=1;k<=i-1;k++){
            db=0;
            for(int j=k;j<=i;j++){
                db+=min(b[j]-b[k],b[i]-b[j]);
            }
            for(int j=2;j<=m;j++){
                f[i][j]=min(f[i][j],f[k][j-1]+db);
            }
        }
    }
    for(int i=1;i<=n;i++){
        db=0;
        for(int j=i;j<=n;j++){
            db+=(b[j]-b[i]);
        }
        op=min(op,f[i][m]+db);
    }
    cout<<op<<endl;
	return 0;
}
posted @ 2025-10-29 21:30  bz02_2023f2  阅读(1)  评论(0)    收藏  举报  来源