UVALive 3983 Robotruck (单调队列,dp)

如果状态定义为序号和重量的话,决策就是下一个垃圾捡或者不减,但是状态数太多了。

如果只定义序号作为状态的话,决策就变成从前面的某个j一直捡到i才送回垃圾。

这就变成了一个区间选最小值的问题,用单调队列维护。复杂度O(n)

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e5+5;
int x[maxn], y[maxn], w[maxn];
int sum_dist[maxn],sum_w[maxn],dist[maxn];
int dq[maxn],d[maxn];
inline int manhattan(int i,int j){ return abs(x[i]-x[j])+abs(y[i]-y[j]); }
inline int f(int i) { return d[i] - sum_dist[i+1] + dist[i+1]; }

//#define LOCAL
int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif
    //sum_dist[0] = 0;x[0] = y[0] = 0; d[0] = 0 dq[0] = 0
    int T; scanf("%d",&T);
    while(T--){
        int C,n; scanf("%d%d",&C,&n);
        for(int i = 1; i <= n; i++){
            scanf("%d%d%d",x+i,y+i,w+i);
            if(i>1) sum_dist[i] = sum_dist[i-1] + manhattan(i,i-1);
            sum_w[i] = sum_w[i-1] + w[i];
            dist[i] = manhattan(i,0);
        }
        int hd = 0,tl = 1;
        for(int i = 1; i <= n; i++){
            while(tl>hd && sum_w[i] - sum_w[dq[hd]] > C) hd++;
            d[i] = f(dq[hd]) + (sum_dist[i] + dist[i]);
            while(tl>hd && f(i) <= f(dq[tl-1])) tl--;
            dq[tl++] = i;
        }
        printf("%d
",d[n]);
        if(T) putchar('
');
    }
    return 0;
}
原文地址:https://www.cnblogs.com/jerryRey/p/4846949.html