[题解] LuoguP4767 [IOI2000]邮局

https://www.luogu.com.cn/problem/P4767

清一色的四边形不等式......

其实分治优化决策单调性DP也是可以的

(f(i,j))表示前(j)个村庄,建(i)个邮局,每个村庄和最近的邮局之间所有距离最小总和是多少。

再设(w(i,j))表示在第(i)个到第(j)个村庄之间建一个邮局最小的距离总和。

根据中位数定理,发现邮局一定建在([i,j])的中间。

于是维护个前缀和啥的就可以(V^2)处理出(w)

然后考虑DP的转移,枚举最后一个邮局建在哪个区间内,即

[f(i,j) = maxlimits_{1 le k le j} { f(i-1,k-1)+w(k,j)} ]

特别的,如果(j<i),那么(f(i,j) = infty)

发现(f(i,...))只会从(f(i-1,...))转移,瞎猜一个决策点也满足单调性,于是分治优化一层的转移即可。

虽然比四边形不等式多一个(log)...但好像跑起来也差不多)

Code:

#include <bits/stdc++.h>

using namespace std;

const int N = 3010;
const int inf = 1e9;
int cost[N][N], s[N][N], x[N];

void solve(int *f, int *g, int l, int r, int pl, int pr) {
  if (l > r || pl > pr) {
    return;
  }   
  auto weight = [&](int i, int j) {
    return cost[i][j];
  };
  if (pl == pr) { 
    for (int i = l; i <= r; i++) {
      f[i] = g[pl - 1] + weight(pl, i);
    }
    return;
  }
  int mid = (l + r) >> 1;
  int pmid = -1;
  int mn = inf * 2;
  for (int i = pl; i <= min(mid, pr); i++) {
    if (g[i - 1] + weight(i, mid) < mn) {
      mn = g[i - 1] + weight(i, mid);
      pmid = i;
    }
  }
  f[mid] = mn;
  solve(f, g, l, mid - 1, pl, pmid);
  solve(f, g, mid + 1, r, pmid, pr);
}

int dp[N][N];

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  int n, m;
  cin >> n >> m;
  for (int i = 1; i <= n; i++) {
    cin >> x[i];
  }   
  for (int i = 1; i <= n; i++) {
    for (int j = i; j <= n; j++) {
      s[i][j] = s[i][j - 1] + x[j];
    }
  }
  for (int i = 1; i <= n; i++) {
    for (int j = i; j <= n; j++) {
      int mid = (i + j) >> 1;
      cost[i][j] = x[mid] * (mid - i + 1) - s[i][mid] + s[mid][j] - x[mid] * (j - mid + 1);
    }
  }             
  dp[1][0] = inf;
  for (int i = 1; i <= n; i++) {
    dp[1][i] = cost[1][i];
  }         
  for (int i = 2; i <= m; i++) {
    solve(dp[i], dp[i - 1], 1, n, 1, n);
    for (int j = 0; j < i; j++) {
      dp[i][j] = inf;
    } 
  }
  cout << dp[m][n] << '
';
  return 0;
}
原文地址:https://www.cnblogs.com/wxq1229/p/13357316.html