P4767 [IOI 2000] 邮局 加强版
一、思路
1、暴力
先忽略数据大小,将村庄坐标按从小到大排序后,做线性DP
设 \(f[i][j]\) 表示在前 i 个村庄设置 j 个邮局的最小距离和
设 \(w(k+1,j)\) 表示在第 k+1 个村庄到第 j 个村庄设置一个邮局的最小距离和
\[f[i][j]=min_{k=0}^{i-1}f[k][j-1]+w(k+1,i)
\]
当邮局的位置 \(j={{l+r}\over 2}\) 时,\(w(l,r)\) 有最小值
设 \(sum[i]=\sum_{j=1}^na[j]\)
\[w(l,r)=a[mid]*(mid-l+1)-(sum[mid]-sum[l-1])+(sum[r]-sum[mid])-a[mid]*(r-mid)
\]
(画图理解)
2、优化 \(O(PV)\)
设 \(s[i][j]\) 表示 \(f[i][j]\) 的最优决策点(使 \(f[i][k]+f[k+1][j]\) 取到最小值的 k 称为 \(f[i][j]\) 的最优决策点),通过打表可以发现单调性, \(s[i][j-1] \leq s[i][j] \leq s[i+1][j]\) ,所以中间节点 k 的选取范围在 \(s[i][j-1]\) 至 \(s[i+1][j]\) 之间
补充:
四边形不等式:对所有 \(a \leq b \leq c \leq d\) , \(w(a,d)+w(b,c)\geq w(a,c)+w(b,d)\)成立
若满足四边形不等式,则说明具有决策单调性,则 \(s[i][j-1] \leq s[i][j] \leq s[i+1][j]\)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int inf=1e9;
int v,p,a[3005],s[3005][3005],f[3005][3005],sum[3005],mn,id;
int add(int l,int r){
int mid=(l+r)>>1;
return a[mid]*(mid-l+1)-(sum[mid]-sum[l-1])+(sum[r]-sum[mid])-a[mid]*(r-mid);
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>v>>p;
for(int i=1;i<=v;i++)
cin>>a[i];
sort(a+1,a+v+1);
for(int i=1;i<=v;i++)
sum[i]=sum[i-1]+a[i];
memset(f,0x3f,sizeof(f));
f[0][0]=0;
for(int j=1;j<=p;j++){
s[v+1][j]=v;//边界
for(int i=v;i>=1;i--){
mn=inf;
for(int k=s[i][j-1];k<=s[i+1][j];k++){
int tmp=add(k+1,i);
if(f[k][j-1]+tmp<mn){
mn=f[k][j-1]+tmp;
id=k;
}
f[i][j]=mn;
s[i][j]=id;
}
}
}
cout<<f[v][p]<<'\n';
return 0;
}

浙公网安备 33010602011771号