zoukankan      html  css  js  c++  java
  • [题解] 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;
    }
    
  • 相关阅读:
    CH02 FPGA设计Verilog基础笔记(二)
    同一个按键短按与长按的区别触发
    树莓派 -- 输入设备驱动 (key) 续2: 转载 Setting up a GPIO-Button “keyboard” on a Raspberry Pi
    树莓派 -- 输入设备驱动 (key) 续1
    树莓派 -- 输入设备驱动 (key)
    树莓派 -- 按键 (key)使用BCM2835 gpio library
    leds-gpio driver 续1
    leds-gpio driver
    使用CSDN-markdown编辑器
    树莓派
  • 原文地址:https://www.cnblogs.com/wxq1229/p/13357316.html
Copyright © 2011-2022 走看看