卧薪尝胆,厚积薄发。
IOI2000 Post Office
Date: Fri Aug 10 22:38:04 CST 2018 In Category: NoCategory

Description:

有 $n​$ 个村庄,第 $i​$ 个在 $p_i​$ ,在其中 $m​$ 个建邮局,问每个村庄走到离其最近的邮局的距离和的最小值。
$k\le n \le 300$

Solution:

设 $w(i,j)$ 为 $[i,j]$ 内建一个邮局 $[i,j]$ 都走到这个邮局的最小代价,发现应该建在中位数即 $p_{\frac {i+j+1}2}$ 上。
有 $\begin{align}w(i,j)=\sum_{k=i}^j |p_k-p_{\frac {i+j+1}2}|=-\sum_{k=i}^{\lfloor\frac {i+j-1}2\rfloor}p_k+\sum_{k=\lfloor\frac {i+j+1}2\rfloor+1}^jp_k\end{align}$
$w(i,j)=w(i,j-1)+p_j-p_{\lfloor\frac{i+j}2\rfloor}$
$w(i,j)=w(i+1,j)-p_i+p_{\lfloor\frac{i+j}2\rfloor}$
$f[i][j]=min{f[i-1][k]+w(k+1,j)}$
发现是经典的 $1D/1D$ 动态规划,只要证明 $w$ 满足四边形不等式和区间包含性即可证明 $f$ 满足决策单调性。
区间包含性显然。
$$w(i,j)+w(i+1,j+1)\le w(i,j+1) + w(i+1,j)$ $
$$2w(i,j)+p_i-p_{\lfloor\frac{i+j}2\rfloor}+p_{j+1}-p_{\lfloor\frac{i+j+2}2\rfloor}\le 2w(i,j)+p_{j+1}-p_{\lfloor\frac {i+j+1}2\rfloor}+p_i-p_{\frac {i+j} 2}$ $
$$-p_{\frac{i+j+2}2}\le-p_{\frac {i+j+1}2}$ $
显然成立。
则 $f$ 满足四边形不等式,且满足 $f[i][i]=0$ ,满足决策单调性。于是 $f[i][j]$ 只用从 $[s[i][j-1],s[i+1][j]]$ 转移即可。
长得和区间 $DP$ 一模一样。
不是很理解。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cctype>
#include<cstring>
using namespace std;
int n,m;
#define MAXN 310
int p[MAXN];
int w[MAXN][MAXN];
int f[MAXN][MAXN];
int s[MAXN][MAXN];
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++i)scanf("%d",&p[i]);
memset(f,0x3f,sizeof(f));
for(int i = 1;i <= n;++i)
{
w[i][i] = 0;
for(int j = i + 1;j <= n;++j)
{
w[i][j] = w[i][j - 1] + p[j] - p[(i + j) / 2];
}
}
for(int i = 0;i <= n;++i)
{
f[i][i] = 0;
s[i][i] = i;
}
for(int l = 2;l <= n - m + 1;++l)
{
for(int i = 1;i <= n - l + 1;++i)
{
int j = i + l - 1;
for(int k = s[i][j - 1];k <= s[i + 1][j];++k)
{
if(f[i][j] > f[i - 1][k - 1] + w[k][j])
{
f[i][j] = f[i - 1][k - 1] + w[k][j];
s[i][j] = k;
}
}
}
}
cout << f[m][n] << endl;
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡