Solution [IOI2000]邮局
题目大意:在(n)个村庄中选(m)个邮局,求最小代价和
四边形不等式
分析:
首先我们假设只有一个邮局,利用初中数学可知邮局放中间是最优秀的
设(w[l][r])为([l,r])内放一个邮局的最小代价和
设(f[i][j])为([1,i])内放(j)个邮局的最小代价和
显然(f[i][j] = min{f[k][j - 1] + w[k + 1][i] quad k in [1,i - 1]})
然后这玩意儿如果(O(n))转移那么复杂度(O(n^3))直接上天,打表等思路证明一下(w)满足四边形不等式,所以有决策单调性
设(m[i][j])为(f[i][j])的最优决策点
有(m[i][j - 1] leq m[i][j] leq m[i + 1][j])
注意邮局坐标要排序
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 3333;
int val[maxn],sum[maxn],w[maxn][maxn],f[maxn][maxn],m[maxn][maxn],n,v;
inline int query(int a,int b){return a <= b ? sum[b] - sum[a - 1] : 0;}
int main(){
ios::sync_with_stdio(false);
cin >> n >> v;
for(int i = 1;i <= n;i++)cin >> val[i];
sort(val + 1,val + 1 + n);
for(int i = 1;i <= n;i++)sum[i] = sum[i - 1] + val[i];
for(int l = 1;l <= n;l++)
for(int r = l;r <= n;r++){
int mid = (l + r) >> 1;
w[l][r] += val[mid] * (mid - l) - query(l,mid - 1);
w[l][r] += query(mid + 1,r) - val[mid] * (r - mid);
}
memset(f,0x3f,sizeof(f));
for(int i = 1;i <= n;i++)f[i][1] = w[1][i];
for(int j = 2;j <= v;j++){
m[n + 1][j] = n;
for(int i = n;i >= 1;i--)
for(int k = m[i][j - 1];k <= m[i + 1][j];k++)
if(f[k][j - 1] + w[k + 1][i] < f[i][j])
f[i][j] = f[k][j - 1] + w[k + 1][i],m[i][j] = k;
}
cout << f[n][v] << '
';
return 0;
}