首页 > 其他分享 >luogu P4677 山区建小学

luogu P4677 山区建小学

时间:2022-09-28 00:33:51浏览次数:54  
标签:10 int luogu 距离 村庄 小学 区间 P4677 define

山区建小学

题目描述

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

输入格式

第1行为n和m,其间用空格间隔。

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

例如

10 3

2 4 6 5 2 4 3 1 3

表示在10个村庄中建3所学校。第1个村庄与第2个村庄距离为2,第2个村庄与第3个村庄距离为4,第3个村庄与第4个村庄距离为6,...,第9个村庄到第10个村庄的距离为3。

输出格式

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

样例 #1

样例输入 #1

10 2
3 1 3 1 1 1 1 1 3

样例输出 #1

18

提示

0 < \(m\) <= \(n\) < 500

0 < \(d_i\) <=100

思路

我们首先考虑一个性质
就是一段区间我们肯定是在中间插点才是最小的 (只插一个)
证明:
首先我们设左边有l个点 右边r个点
假设我们现在就在中间点 我们往左移一单位就是总距离之和+r-l 而一直往左只会让r更多
所以这个是个单调减的 左边也是如此
所以我们知道一段区间中间才是最好的
我们预处理出每个区间的f[l][r]表示区间内的距离之和的min
问题就转化为了我们一个大区间怎么选m个小区间正好全部放满的同时还要最小
我们直接设dp[i][j]表示前[1,ai]区间选了j个区间
而我们状态转移只要枚举右端点在ai的区间即可
dp[i][j]=min{dp[k][j-1]+f[k+1][i]}

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
const int M = 998244353;
const int mod = 1e9+7;
#define int long long
#define endl '\n'
#define all(x) (x).begin(),(x).end()
#define YES cout<<"YES"<<endl;
#define NO cout<<"NO"<<endl;
#define _ 0
#define pi acos(-1)
#define INF 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int a[510],dp[510][510],f[510][510];
void solve() {
    int n,m;cin>>n>>m;
    for(int i=2;i<=n;i++){
        cin>>a[i];
        a[i]+=a[i-1];
    }
    for(int i=1;i<=n;i++)
        for(int j=i;j<=n;j++){
            int mid=i+j>>1;
            for(int k=i;k<=j;k++)f[i][j]+=abs(a[mid]-a[k]);
        }
    memset(dp,0x3f3f,sizeof dp);
    dp[0][0]=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=min(i,m);j++)
            for (int k = j - 1; k <= i - 1; k++)
                dp[i][j] = min(dp[i][j], dp[k][j - 1] + f[k + 1][i]);
    cout<<dp[n][m]<<endl;
}
signed main(){
    fast
    int T;T=1;
    while(T--) {
        solve();
    }
    return ~~(0^_^0);
}

标签:10,int,luogu,距离,村庄,小学,区间,P4677,define
From: https://www.cnblogs.com/ycllz/p/16736559.html

相关文章

  • 小学二年级都能看懂的 虚树学习笔记
    过不去那道题?事实:它数据范围很大而且每一次询问都得O(n)暴力出题人最坏了!介绍……虚树!介绍先看这么一道题P2495[SDOI2011]消耗战题目大意:每一次给k个特殊点,每次......
  • luogu P1043 [NOIP2003 普及组] 数字游戏
    [NOIP2003普及组]数字游戏题目描述丁丁最近沉迷于一个数字游戏之中。这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容......
  • luogu P1385 密令
    密令题目描述给定一小写字母串\(s\),每次操作你可以选择一个\(p\)(\(1\leqp\lt|s|\))执行下述修改中的任意一个:将\(s_p\)改为其字典序\(+1\)的字母,将\(s_{p+1}......
  • 【luogu P6419】Kamp(换根DP)
    Kamp题目链接:luoguP6419题目大意一棵树上有一些点有人,边有通过的长度,然后对于每个点,你从这个点出发经过所有人(不用回到原来位置)的最短时间。其它人不会动,只有你去找人......
  • [luogu3980]志愿者招募
    记$x_{i}$为第$i$类志愿者数量$,y_{j}=\sum_{j\in[s_{i},t_{i}]}x_{i}-a_{j}$​,则问题即$$\foralli\in[1,m],x_{i}\ge0\\\forallj\in[1,n],y_{j}\ge0\\y_{1}-\sum_{......
  • 【luogu CF1109E】Sasha and a Very Easy Test(线段树)
    SashaandaVeryEasyTest题目链接:luoguCF1109E题目大意维护一个长度为n的序列,有区间乘,单点除(保证能整除),区间求和答案对p取模。p不一定是质数。思路麻了考场......
  • [luogu p8251] [NOI Online 2022 提高组] 丹钓战
    [P8251NOIOnline2022提高组]丹钓战-洛谷|计算机科学教育新生态(luogu.com.cn)容易发现对于一次查询\([L,R]\),\(L\)一定是第一个入栈的,也是成功的,答案至少为......
  • luogu P1052 [NOIP2005 提高组] 过河
    [NOIP2005提高组]过河题目描述在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳......
  • luogu P2233 [HNOI2002]公交车路线
    [HNOI2002]公交车路线题目描述在长沙城新建的环城公路上一共有\(8\)个公交站,分别为A、B、C、D、E、F、G、H。公共汽车只能够在相邻的两个公交站之间运行,因此你从某一......
  • luogu P1772 [ZJOI2006] 物流运输 (dp, 最短路)
    https://www.luogu.com.cn/problem/P1772虽然是图论背景,但是1-n天之间是线性关系。没法贪心决策,考虑dp:我本来写的dp是i-1转移到i,但是这样没法处理哪一天能走哪些最短路......