• ZOJ 3031 Robotruck (dp + 单调队列)


    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=2029

      搞了一个多小时的一道DP&&单调队列题。这题在ACM-ICPC Live Archive中有相似的一题,不过在LA中,每个位置的物品重量不为0,这样就限制了寻找上一层dp值的范围只在下标为i-100~i 之间,复杂度是O(CN)。可是到了ZOJ,dp值的寻找就有可能要把之前所有已经处理的状态都找一遍,这样子,同样的做法就果断超时了。

      不过可以轻易的发现,dp是线性的,而且最优值是可以通过某种转换方式表示出来。同时,因为物品的发放顺序有所限制,所以可以直接用前缀和来快速找到某个区间的距离之和。

    代码如下:

    View Code
     1 LL dp, wSum[N], dSum[N];
     2 int x[N], y[N];
     3 
     4 void input(int n) {
     5     LL w;
     6     wSum[0] = dSum[0] = 0ll;
     7     REP_1(i, n) {
     8         scanf("%d%d%lld", &x[i], &y[i], &w);
     9         wSum[i] = wSum[i - 1] + w;
    10         dSum[i] = dSum[i - 1] + abs(x[i] - x[i - 1]) + abs(y[i] - y[i - 1]);
    11     }
    12 }
    13 
    14 PRIQ<pair<LL, int>, vector<pair<LL, int> >, greater<pair<LL, int> > > Q;
    15 
    16 LL work(int n, int w) {
    17     int p = 1;
    18     while (!Q.empty()) Q.pop();
    19     Q.push(MPR(abs(x[1]) + abs(y[1]) - dSum[1], 0));
    20     REP_1(i, n) {
    21         while (wSum[i] - wSum[p - 1] > w) p++;
    22         while (Q.top().SE + 1 < p) Q.pop();
    23         LL fi = Q.top().FI;
    24         dp = fi + abs(x[i]) + abs(y[i]) - (dSum[i + 1] - dSum[i]) + abs(x[i + 1]) + abs(y[i + 1]);
    25         Q.push(MPR(dp, i));
    26     }
    27     dp += dSum[n] - abs(x[n + 1]) - abs(y[n + 1]) + (dSum[n + 1] - dSum[n]);
    28     return dp;
    29 }
    30 
    31 int main() {
    32     int T, n, m;
    33     while (~scanf("%d", &T)) {
    34         while (T--) {
    35             scanf("%d%d", &m, &n);
    36             input(n);
    37             cout << work(n, m) << endl;
    38         }
    39     }
    40     return 0;
    41 }

    ——written by Lyon

  • 相关阅读:
    Android第四次作业
    Android第三次作业
    android 第一次作业
    团队作业-项目答辩
    团队作业2
    软工作业--团队作业2
    软件工程—团队作业1
    软件工程第一次作业
    Android第四次作业
    Android 第三次作业
  • 原文地址:https://www.cnblogs.com/LyonLys/p/zoj_3031_Lyon.html
Copyright © 2020-2023  润新知