【DP】【Greedy】[CodeForces - 581E] Kojiro and Furrari

CodeForces - 581E

分析:根据题意(f < e),只能向右走,如果向左走,必定还要向右走,会消耗更多的油。
f[i][1/2]表示以空油箱从i向右走需要消耗的93#/95#油;
因为要求尽量多使用编号较大的油,所以对于i,它的编号为ai,如果在它向右s以内有编号aj>=ai,最近的为j,则加油至正好能到达j,否则,加满,然后在保证编号尽量大的情况下到最远的一个加油站加油。

可以用一个队列来保存离i距离<=s的加油站。

其实起点也可以当做一个汽油编号为3加油站,那么在dp的时候就可以直接用O(1)的时间得出答案,而起点不可以压入队列。

比官方题解好理解多了吧 :-D

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 200000
int e,s,n,m,st,q[4][MAXN+10];    //3个队列存储编号分别为123的加油站
typedef pair<int,int>pii;
pii a[MAXN*2+10],f[MAXN*2+10],ans[MAXN+10];   //起点和加油站存在一起
int main()
{
    int i,front[4],rear[4],j;
    memset(f,0xff,sizeof f);
    memset(ans,0xff,sizeof ans);
    scanf("%d%d%d%d",&e,&s,&n,&m);
    for(i=1;i<=n;i++)
        scanf("%d%d",&a[i].second,&a[i].first);
    for(i=1;i<=m;i++){
        scanf("%d",&a[i+n].first);
        a[i+n].second=3+i;        //存储询问顺序的同时和普通加油站作区别
    }
    sort(a+1,a+n+m+1);
    for(i=1;i<=n+m;i++)
        if(a[i].first>e)
            break;
    if(a[i].first==e)
        i--;
    a[i].first=e,a[i].second=3;
    e=i;
    f[e]=make_pair(0,0);
    q[3][0]=e;
    front[3]=rear[3]=0;
    front[2]=front[1]=0;
    rear[2]=rear[1]=-1;
    for(i=e-1;i;i--){
        int t=0x7fffffff;
        while(front[3]<=rear[3]&&a[q[3][front[3]]].first-a[i].first>s)
            front[3]++;
        while(front[2]<=rear[2]&&a[q[2][front[2]]].first-a[i].first>s)
            front[2]++;
        while(front[1]<=rear[1]&&a[q[1][front[1]]].first-a[i].first>s)
            front[1]++;
        if(a[i].second>3){
            for(j=3;j>0;j--)
                if(front[j]<=rear[j]){
                    if(j==1)
                        ans[a[i].second-3]=make_pair(f[q[j][front[j]]].first-s+a[q[j][front[j]]].first-a[i].first,f[q[j][front[j]]].second);
                    else if(j==2)
                        ans[a[i].second-3]=make_pair(f[q[j][front[j]]].first,f[q[j][front[j]]].second-s+a[q[j][front[j]]].first-a[i].first);
                    else
                        ans[a[i].second-3]=make_pair(f[q[j][front[j]]].first,f[q[j][front[j]]].second);
                    break;
            }
            if(!i)
                ans[a[i].second]=make_pair(-1,-1);
            continue;
        }
        for(j=3;j>=a[i].second;j--)
            if(front[j]<=rear[j])
                t=min(t,q[j][rear[j]]);
        if(t==0x7fffffff)
            for(;j;j--)
                if(front[j]<=rear[j]){
                    t=q[j][front[j]];
                    break;
                }
        if(t==0x7fffffff)
            break;
        f[i]=f[t];
        if(a[t].second>=a[i].second){
            if(a[i].second==1)
                f[i].first+=a[t].first-a[i].first;
            else if(a[i].second==2)
                f[i].second+=a[t].first-a[i].first;
        }
        else{
            if(a[i].second==2){
                f[i].second+=s;
                f[i].first-=s-a[t].first+a[i].first;
            }
            else if(a[i].second==3){
                if(a[t].second==2)
                    f[i].second-=s-a[t].first+a[i].first;
                else
                    f[i].first-=s-a[t].first+a[i].first;
            }
        }
        q[a[i].second][++rear[a[i].second]]=i;
    }
    for(i=1;i<=m;i++)
        printf("%d %d\n",ans[i].first,ans[i].second);
}
posted @ 2015-09-29 22:35  outer_form  阅读(260)  评论(0编辑  收藏  举报