题目大意:
给定一条数轴上的n个点,安放m个邮局,使得每一个点距离它最近的邮局的距离和最小。
思路:
最后答案的计算必定是整个数轴分成了m个部分然后每一个部分都取它中位数来建设邮局。
于是我们依次在数轴上面添加每一个部分,记dp[i][j]表示前i个点总共放置了j个邮局的最小代价,于是我们可以通过dp[k][j-1]来转移,即在k这个点后面的这一部分新开一个邮局并且在中位数这里。方程为:
dp[i][j]=min(dp[k][j−1]+w[k+1][i])
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
k
]
[
j
−
1
]
+
w
[
k
+
1
]
[
i
]
)
现在考虑怎么优化这个DP,注意到这里的转移似乎是一个区间的形式,于是我们把DP数组的两维反过来即有:
dp[j][i]=min(dp[j−1][k]+w[k+1][i])
d
p
[
j
]
[
i
]
=
m
i
n
(
d
p
[
j
−
1
]
[
k
]
+
w
[
k
+
1
]
[
i
]
)
现在就可以很明显地看出来这是一个区间DP的形式了,所以我们要想用四边形不等式去优化,
本蒟蒻对四边形不等式这一块了解甚少,以上的
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
typedef long long ll;
using namespace std;
template<typename T>void read(T &_){
T __=0,mul=1; char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')mul=-1;
ch=getchar();
}
while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
_=__*mul;
}
void File(){
freopen("luogu4767.in","r",stdin);
freopen("luogu4767.out","w",stdout);
}
const int maxn=3000+10;
const int maxm=300+10;
int n,m;
int a[maxn],dp[maxn][maxn],w[maxn][maxn],p[maxn][maxn];
void init(){
read(n); read(m);
REP(i,1,n)read(a[i]);
REP(j,2,n)REP(i,1,n-j+1){
int l=i,r=i+j-1,mid=(l+r)>>1;
if((l+r)%2)w[l][r]=w[l][r-1]+abs(a[mid]-a[r]);
else w[l][r]=w[l+1][r]+abs(a[mid]-a[l]);
}
//REP(i,1,n)REP(j,i+1,n)cout<<(w[i+1][j-1]<=w[i][j])<<endl;
}
void work(){
memset(dp,63,sizeof(dp));
dp[0][0]=0;
REP(i,1,n)DREP(j,min(i,m),1){
int l=p[i-1][j],r=p[i][j+1];
if(!r)r=i-1;
REP(k,l,r){
if(dp[k][j-1]+w[k+1][i]<dp[i][j]){
dp[i][j]=dp[k][j-1]+w[k+1][i];
p[i][j]=k;
}
}
}
printf("%d\n",dp[n][m]);
}
int main(){
File();
init();
work();
return 0;
}