ZOJ 3699 Dakar Rally 解题报告

题意:给油箱容量,n个有顺序的点,给出从当前点到下一个点的距离,单位耗油量,汽油的单价。每个站都能加不超过油箱容量的油。求到终点的最小花费。
解法:本着贪心的原则,应该尽量在便宜的地方多加油。
所以模拟汽车行驶的过程中,在比当前位置汽油便宜的站能加要尽量加满(如果之后发现不是最优的就减去),并记录每一站剩余的可用油量,和到当前站油箱中剩余的汽油(因为要保证不超过油箱容量)。而花费是统计从当前站恰好到下一站使用的最便宜的汽油的价钱,即队首汽油。

用单调队列维护还能加油的区间的单价最小值,每次需要加油的时候只需要从队首取油就行,用完即可出队列。

//Memory: 4876 KB
//Time: 250 MS
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <iostream>
#include <map>
#include <cmath>
using namespace std;
const int maxn = 200005;
const int inf = 1111111111;
long long q[maxn],head,tail,cost[maxn];
long long p[maxn];

int main()
{
    //freopen("in.txt","r",stdin);
    int ca,n,m,use[maxn];
    int u,v;
    long long w;
    bool flag;
    scanf("%d",&ca);
    while(ca--)
    {
        scanf("%d%d",&n,&m);
        flag = 1;
        for(int i = 1; i <= n; i++)
        {
            scanf("%d%d%d",&u,&v,&p[i]);
            w=(long long)u*v;
            if(w>m) flag = 0;
            else cost[i]=u*v;
        }
        if(flag == 0)
        {
            printf("Impossible\n");
            continue;
        }
        head = tail = 0;
        long long ans = 0;
        long long gas=0;
        for(int i = 1; i <= n; i++)
        {
            while(head<tail&&p[i]<p[q[tail-1]]) gas-=use[--tail];
            use[tail]=m - gas;
            q[tail++]=i;
            //cout<<gas<<" "<<m-gas<<endl;
            gas = m - cost[i];
            //cout<<gas<<endl;
            while(cost[i])
            {
                if(use[head]<=cost[i])
                {
                    cost[i]-=use[head];
                    ans+=use[head]*p[q[head]];
                    head++;
                }
                else
                {
                    use[head]-=cost[i];
                    ans+=cost[i]*p[q[head]];
                    cost[i]=0;
                }
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}



你可能感兴趣的:(ZOJ 3699 Dakar Rally 解题报告)