貌似$BZOJ$上并没有这个题。。。

是嫌这个题水了么。。。

还是要氪金权限号???

这里附上洛谷的题面:洛谷P4767 [IOI2000]邮局

题目描述

高速公路旁边有一些村庄。高速公路表示为整数轴,每个村庄的位置用单个整数坐标标识。没有两个在同样地方的村庄。两个位置之间的距离是其整数坐标差的绝对值。

邮局将建在一些,但不一定是所有的村庄中。为了建立邮局,应选择他们建造的位置,使每个村庄与其最近的邮局之间的距离总和最小。

你要编写一个程序,已知村庄的位置和邮局的数量,计算每个村庄和最近的邮局之间所有距离的最小可能的总和。

输入输出格式

输入格式:

第一行包含两个整数:第一个是村庄$V$的数量,第二个是邮局的数量$P$,$1 \leq P \leq 300$,$P \leq V \leq 3000$.

第二行包含$V$个整数。这些整数是村庄的位置。对于每个位置$X$,认为$1 \leq X \leq 10000$。

输出格式:

第一行包含一个整数$S$,它是每个村庄与其最近的邮局之间的所有距离的总和。

输入输出样例

输入样例#1: 复制

10 5
1 2 3 6 7 9 11 22 44 50
输出样例#1: 复制

9

说明

对于40%的数据,$V \leq 300$


题解Here!

首先这是个区间$DP$对吧。

我们一步一步来分析:

首先要将村庄位置排个序,不用多说。

下面开始$DP$。

$No. 1:\text{普通DP}$:

设$dp[i][j]$表示前$i$个村庄中建了$j$个邮局的最优方案。

转移方程长这个样:

$$dp[i][j]=\max\{\ dp[k][j-1]+dis(k+1,i)\ |\ k\in[0,i)\}$$

其中$dis(l,r)$表示在$[l,r]$这个区间内的村庄中建一个邮局对答案的贡献。

利用人类智慧可知把邮局建在中间花费最少。。。

复杂度上限是$O(n^3m)$,实测可以$40\text{分}$。

代码如下:

inline int abs(int x){return x>0?x:-x;}
inline int dis(int l,int r){
int mid=(l+r)>>1,s=0;
for(int i=l;i<=r;i++)s+=abs(pos[i]-pos[mid]);//pos是村庄位置
return s;
}
void work(){
dp[0][0]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m&&j<=i;j++)
for(int k=0;k<i;k++)
dp[i][j]=min(dp[i][j],dp[k][j-1]+dis(k+1,i));
printf("%d\n",dp[n][m]);
}

$No. 2:\text{普通DP+优化}$:

我们发现我们的求贡献还要$O(n)$的复杂度,考虑对其进行优化。

我们知道:

$$dis(l,r)=\sum_{i=l}^r|pos_i-pos_{mid}|,mid=\frac{l+r}{2}$$

因为我们的$pos$是有序的,于是:

$$dis(l,r)=\sum_{i=l}^{mid-1}(pos_{mid}-pos_i)+\sum_{i=mid+1}^r(pos_i-pos_{mid}),mid=\frac{l+r}{2}$$

显然拆开:

$$dis(l,r)=(mid-l)pos_{mid}-\sum_{i=l}^{mid-1}pos_i+\sum_{i=mid+1}^rpos_i-(r-mid)pos_{mid},mid=\frac{l+r}{2}$$

合并:

$$dis(l,r)=(2mid-l-r)pos_{mid}+\sum_{i=mid+1}^rpos_i-\sum_{i=l}^{mid-1}pos_i,mid=\frac{l+r}{2}$$

注意,这个地方$2mid-l-r \neq 0$,因为实际算$mid$时,算的其实是$\lfloor\frac{l+r}{2}\rfloor$。

但是这个并不影响复杂度,所以可以保留。

关键是后面那两个$\sum$怎么整?

前缀和!

设$sum(x)=\sum_{i=1}^xpos_i$,则:

$$\left.\begin{array}{}dis(l,r)&=&(2mid-l-r)pos_{mid}+(sum(r)-sum(mid))-(sum(mid-1)-sum(l-1))\\&=&(2mid-l-r)pos_{mid}+sum(l-1)+sum(r)-sum(mid)-sum(mid-1)\end{array}\right.$$

于是预处理前缀和,就可以$O(1)$计算$dis(l,r)$了!

复杂度$O(n^2m)$,实测$60\text{分}$。

代码如下:

inline int dis(int l,int r){
int mid=(l+r)>>1;
return ((sum[r]-sum[mid])-(sum[mid-1]-sum[l-1])+(mid*2-l-r)*pos[mid]);
}
void work(){
dp[0][0]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m&&j<=i;j++)
for(int k=0;k<i;k++)
dp[i][j]=min(dp[i][j],dp[k][j-1]+dis(k+1,i));
printf("%d\n",dp[n][m]);
}

$No. 3:\text{DP+四边形不等式}$:

四边形不等式优化就是:

在$DP$过程中满足:

$$dp[a][c]+dp[b][d]<=dp[a][d]+dp[b][c]$$

并且决策具有单调性。

对于这题,我们发现,$dp[i][j]$的决策只能从$dp[i][j-1],dp[i+1][j]$中选一个进行转移。

于是就可以用四边形不等式优化了!

到此,我们证明了这个题其实是个板子题。。。

记得要倒序$DP$。

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define MAXN 3010
using namespace std;
int n,m;
int pos[MAXN],sum[MAXN],from[MAXN][MAXN],dp[MAXN][MAXN];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
inline int dis(int l,int r){
int mid=(l+r)>>1;
return ((sum[r]-sum[mid])-(sum[mid-1]-sum[l-1])+(mid*2-l-r)*pos[mid]);
}
void work(){
for(int j=2;j<=m;j++){
from[n+1][j]=n;
for(int i=n;i>=1;i--){
for(int k=from[i][j-1];k<=from[i+1][j];k++){
if(dp[k][j-1]+dis(k+1,i)<dp[i][j]){
dp[i][j]=dp[k][j-1]+dis(k+1,i);
from[i][j]=k;
}
}
}
}
printf("%d\n",dp[n][m]);
}
void init(){
n=read();m=read();
memset(dp,127,sizeof(dp));
for(int i=1;i<=n;i++)pos[i]=read();
sort(pos+1,pos+n+1);
sum[0]=0;
for(int i=1;i<=n;i++){
sum[i]=sum[i-1]+pos[i];
dp[i][1]=dis(1,i);
}
}
int main(){
init();
work();
return 0;
}

BZOJXXXX: [IOI2000]邮局——四边形不等式优化初探的更多相关文章

  1. P4767 [IOI2000]邮局 - 平行四边形不等式优化DP

    There is a straight highway with villages alongside the highway. The highway is represented as an in ...

  2. POJ 1160 四边形不等式优化DP Post Office

    d(i, j)表示用i个邮局覆盖前j个村庄所需的最小花费 则有状态转移方程:d(i, j) = min{ d(i-1, k) + w(k+1, j) } 其中w(i, j)的值是可以预处理出来的. 下 ...

  3. 【无聊放个模板系列】HDU 3506 (四边形不等式优化DP-经典石子合并问题[环形])

    #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #inc ...

  4. 区间DP的四边形不等式优化

    今天上课讲DP,所以我学习了四边形不等式优化(逃 首先我先写出满足四边形不等式优化的方程:

  5. hdu 2829 Lawrence(四边形不等式优化dp)

    T. E. Lawrence was a controversial figure during World War I. He was a British officer who served in ...

  6. hdu 3480 Division(四边形不等式优化)

    Problem Description Little D is really interested in the theorem of sets recently. There’s a problem ...

  7. 区间dp之四边形不等式优化详解及证明

    看了那么久的四边形不等式优化的原理,今天终于要写一篇关于它的证明了. 在平时的做题中,我们会遇到这样的区间dp问题 它的状态转移方程形式一般为dp[i][j]=min(dp[i][k]+dp[k+1] ...

  8. [NOI1995]石子合并 四边形不等式优化

    链接 https://www.luogu.org/problemnew/show/P1880 思路 总之就是很牛逼的四边形不等式优化 复杂度\(O(n^2)\) 代码 #include <ios ...

  9. HDU 2829 区间DP & 前缀和优化 & 四边形不等式优化

    HDU 2829 区间DP & 前缀和优化 & 四边形不等式优化 n个节点n-1条线性边,炸掉M条边也就是分为m+1个区间 问你各个区间的总策略值最少的炸法 就题目本身而言,中规中矩的 ...

随机推荐

  1. 转: android 实现效果特效

    一. 各种控件效果 http://www.jcodecraeer.com/plus/list.php?tid=31&TotalResult=990&PageNo=7

  2. 系统重装 JUJUMAO VHD安装WIN7解析

    1 把原有系统分区一个删除(使用第三方分区工具如PM或者PQ)并新建一个系统分区(也可以同时新建其他分区如D盘,E盘,但是一定要把C盘设置为NTFS格式并且活动的!)   2 将JUJUMAO_VHD ...

  3. 关于XSuperMES项目使用的PDF框架

    我在曾经的项目中使用的是pdfbox.在读取中文文档时能够读出大部分的文字,可是在数字.分页等地方还是不可避免的出现乱码. 于是我在网上搜索,看有没有什么解决方法.看到有说法: "PDFBo ...

  4. python--pipe

    1.pipe 除了使用队列外,还可以使用管道在进程间执行消息传递 pipe([]duplex) 在进程间创建一条管道,并返回元组(conn1,conn2),其中conn1和conn2是表示管道两端的C ...

  5. python文件备份脚本

    import osimport time source = ['D:\\MyDrivers\hotfix']   #这里可以用自然字符串表示r',因为windows下的分隔符与python的有冲突,所 ...

  6. 使用AlloyLever来搞定开发调试发布,错误监控上报,用户问题定位

    传送门: # gituhbhttps://github.com/AlloyTeam/AlloyLever # 官网https://alloyteam.github.io/AlloyLever/ 下载和 ...

  7. 解密和解压浏览器上加密的js文件

    F12 -> 进入Sources -> 找到任意一个加密的js文件,如图 点击最下方的 {} 即可解压

  8. jar包解压与打包

    首先感谢大神的指导:https://blog.csdn.net/mr_pang/article/details/47028921 1.首先准备一个能运行的jar文件,我们使用第三方解压工具进行解压wi ...

  9. 在oracle11g中配置多个DataGuard物理备机

    >> from zhuhaiqing.info 主机配置 alter system set DB_UNIQUE_NAME='starboss' scope=spfile; alter sy ...

  10. freemarker在xml文件中遍历list数据

    delete   from pub_channelpackage   where channelcode = :channelcode   and channeltype = :channeltype ...