luogu4677山区建小学题解--区间DP
题目链接
https://www.luogu.org/problemnew/show/P4677
分析
这道题方法跟之前题不一样,我们相当于枚举一个左右端点来线性扩展,同时划分断点进行决策
\(f[i][j]\)表示在前\(i\)个村庄中建立\(j\)个小学的最小距离总和
我们将枚举到第\(i\)个村庄作为阶段,修了\(j\)所小学作为状态,通过枚举断点\(k\)来分割第\(j\)所小学与前\(j-1\)所小学
也就是说我们判断\(f[k][j-1]\)加上将新加入的第\(j\)座小学建在后面的第\(k+1\)到第\(i\)座村庄中作出的贡献(也就是新产生的距离,我们假设\(f[k][j-1]\)已经是最优的)是否更优,那么怎么这个贡献怎么求呢呢?比较显然当小学建在\([k+1,i]\)中点处产生的新距离之和最小.为了快速求我们可以先预处理出来
状态转移
memset(f,0x3f,sizeof(f));
    f[0][0]=0;
    for(ri i=1;i<=n;i++){//枚举第几座村庄
        for(ri j=1;j<=min(i,m);j++){//枚举修了多少小学
            for(ri k=j-1;k<i;k++){//断点,枚举前j-1所小学都建在了[1,k]这个区间村庄内
                f[i][j]=min(f[i][j],f[k][j-1]+dis[k+1][i]);
            }
        }
    }
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <cmath>
#define ll long long
#define ri register int
using std::min;
using std::abs;
using std::max;
template <class T>inline void read(T &x){
    x=0;int ne=0;char c;
    while(!isdigit(c=getchar()))ne=c=='-';
    x=c-48;
    while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
    x=ne?-x:x;return ;
}
const int maxn=505;
const int inf=0x7fffffff;
int f[maxn][maxn],s[maxn][maxn],dis[maxn][maxn];
int n,m,pos[maxn];
/*inline int dis(int l,int r){
    int mid=(l+r)>>1,x=0;
    for(ri i=l;i<=r;i++)x+=abs(pos[i]-pos[mid]);
    return x;
}*/
int main(){
    read(n),read(m);
    for(ri i=2;i<=n;i++){
        read(pos[i]);
        pos[i]+=pos[i-1];
    }
    for(ri i=1;i<=n;i++){
    	for(ri j=i;j<=n;j++){
    		s[i][j]+=s[i][j-1]+pos[j];
        }
    }
    for(ri l=1;l<=n;l++){
        for(ri r=l;r<=n;r++){
            int mid=(l+r)>>1;
            dis[l][r]+=(mid-l)*pos[mid]-s[l][mid-1];
            dis[l][r]+=s[mid+1][r]-(r-mid)*pos[mid];
        }
    }
    memset(f,0x3f,sizeof(f));
    f[0][0]=0;
    for(ri i=1;i<=n;i++){//枚举第几座村庄
        for(ri j=1;j<=min(i,m);j++){//枚举修了多少小学
            for(ri k=j-1;k<i;k++){//断点,枚举前j-1所小学都建在了[1,k]这个区间村庄内
                f[i][j]=min(f[i][j],f[k][j-1]+dis[k+1][i]);
            }
        }
    }
    printf("%d\n",f[n][m]);
    return 0;
}
luogu4677山区建小学题解--区间DP的更多相关文章
- 山区建小学(区间dp+前缀和+预处理)
		[题目描述] 政府在某山区修建了一条道路,恰好穿越总共m个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往.已知任意两个相邻的村庄之间的距离为di(为正整数),其中,0 < i ... 
- 7624:山区建小学(划分dp)
		7624:山区建小学 查看 提交 统计 提问 总时间限制: 1000ms 内存限制: 65536kB 描述 政府在某山区修建了一条道路,恰好穿越总共m个村庄的每个村庄一次,没有回路或交叉,任意两个村庄 ... 
- P4677 山区建小学|区间dp
		P4677 山区建小学 题目描述 政府在某山区修建了一条道路,恰好穿越总共nn个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往.已知任意两个相邻的村庄之间的距离为di 为了提高山区 ... 
- 山区建小学(区间DP)
		山区建小学 时间限制: 1 Sec 内存限制: 128 MB提交: 17 解决: 5[提交][状态][讨论版][命题人:quanxing] 题目描述 政府在某山区修建了一条道路,恰好穿越总共m个村 ... 
- 【OpenJudge7624】【区间DP】山区建小学
		山区建小学 总时间限制: 1000ms 内存限制: 65536kB [描述] 政府在某山区修建了一条道路,恰好穿越总共m个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往.已知任意两 ... 
- #DP# ----- OpenJudge山区建小学
		没有记性.到DP不得不写博了,三天后又忘的干干净净.DP是啥 :-) 一道久到不能再久的题了. OpenJudge 7624:山区建小学 总时间限制: 1000ms 内存限制: 65536k ... 
- NOI题库7624 山区建小学(162:Post Office / IOI2000 POST OFFICE [input] )
		7624:山区建小学 Description 政府在某山区修建了一条道路,恰好穿越总共m个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往.已知任意两个相邻的村庄之间的距离为di(为 ... 
- Blocks题解(区间dp)
		Blocks题解 区间dp 阅读体验...https://zybuluo.com/Junlier/note/1289712 很好的一道区间dp的题目(别问我怎么想到的) dp状态 其实这个题最难的地方 ... 
- luogu P4677 山区建小学 |dp
		题目描述 政府在某山区修建了一条道路,恰好穿越总共nnn个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往.已知任意两个相邻的村庄之间的距离为did_idi(为正整数),其中,0& ... 
随机推荐
- JAVA基于File的基本的增删改查
			直接上代码 public class TestFile { /** * 创建目录 * @param filename 路径 */ public static void createFile(Strin ... 
- Java同步数据结构之DelayQueue/DelayedWorkQueue
			前言 前面介绍了优先级队列PriorityBlockingQueue,顺带也说了一下PriorityQueue,两者的实现方式是一模一样的,都是采用基于数组的平衡二叉堆实现,不论入队的顺序怎么样,ta ... 
- Oracle查询表和字段
			查看表字段.类型.注释 SELECT A.COLUMN_NAME,B.comments,A.DATA_TYPE FROM USER_TAB_COLUMNS A LEFT JOIN user_col_c ... 
- MySQL表的创建与维护
			一.导入测试数据 [root@server ~]# wget https://launchpadlibrarian.net/24493586/employees_db-full-1.0.6.tar.b ... 
- [Scikit-learn] 1.5 Generalized Linear Models -  SGD for Regression
			梯度下降 一.亲手实现“梯度下降” 以下内容其实就是<手动实现简单的梯度下降>. 神经网络的实践笔记,主要包括: Logistic分类函数 反向传播相关内容 Link: http://pe ... 
- Swift加载Xib创建的Controller
			Xib显示如下: <注意箭头处即可> 按住Control键,点击Files'owner拖动到View即可. 加载该控制器如下: func registerClick() { let reg ... 
- vim实现批量注释和批量删除注释
			批量注释 1.进入文档,vim test.txt 后,按住ctrl+v进入VISUAL BLOCK模式,上下选择需要注释的行 2.按大写键,再按i,或者直接按shift+i,进入INSERT模式,输入 ... 
- Fabric1.4 背书策略 .yam文件
			{ identities: [ // 以下几项自动编号为[0,1,2] { role: { name: "member", mspId: "peerOrg1" ... 
- 2019-10-20  李宗盛  linux
			Linux Linux简介(了解) Linux介绍:Linux是类UNIX计算机的统称 Linux操作系统的内核也是Linux Linux是由芬兰大学生Linux Torvalds于1991年编写 L ... 
- 编译Android系统
			官方网址: http://source.android.com/source/building.html 下面摘录相关内容: Downloading and Building The Android ... 
