题解 P4767 【[IOI2000]邮局】

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] << '\n';
    return 0;    
}

猜你喜欢

转载自www.cnblogs.com/colazcy/p/11622090.html