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