【NCPC2017-2018-gym101572-A.Airport Coffee 】 線段樹+分類討論DP

Airport Coffee

題目鏈接:

https://codeforces.com/gym/101572/problem/A

Description

在這裏插入圖片描述

Input

在這裏插入圖片描述

Output

在這裏插入圖片描述

Sample Input

100000 100 138 60 300
5
5000 20000 50000 55000 75000

Sample Output

2
0 3

題意

00這個位置出發走到ll這個位置,速度爲aa,路上有nn個咖啡店,可以選擇在某個咖啡店買或者不買咖啡,如果選擇買咖啡,需要用tt的時間等咖啡變涼,在這tt的時間內速度爲aa,之後可以喝咖啡走rr時間的路,在這期間速度爲bb。擁有咖啡的同時仍然可以買咖啡。問走到ll這個位置的最短時間。

題解

首先這道題要考慮倒着做,因爲最後一個咖啡店選擇喝/不喝咖啡到達l的時間是確定的,我們只要倒着推就可以。

之後我們考慮從i這個點到達終點的最優值一定可以從某個j咖啡店轉移過來,我們怎麼保證最優的。

首先分析一下在i這個點喝咖啡之後,一共有以下三個區域。

在這裏插入圖片描述
首先通過二分找出所有在每個區域中的最左咖啡店和最右咖啡店。

設當前點的位置爲pos[i]pos[i],選擇的咖啡店的位置爲pos[j]pos[j]

dp[i]dp[i]爲從i咖啡店走到終點的最短時間。

分析C區域

dp[i]=(dis[j]dis[i]atbra+dp[j]+t+r)dp[i] = (\frac{dis[j]-dis[i]-a*t-b*r}{a}+dp[j]+t+r)

我們發現dp[i]只和dis[j]a+dp[j]\frac{dis[j]}{a}+dp[j]有關,其他都是常量,所以我們只要用一棵線段樹存儲這個信息即可。

分析B區域

dp[i]=(dis[j]dis[i]atb+t+dp[j])dp[i]=(\frac{dis[j]-dis[i]-a*t}{b}+t+dp[j])

我們發現dp[j]只和dis[j]b+dp[j]\frac{dis[j]}{b}+dp[j]有關,其他都是常量,所以我們只要用一棵線段樹存儲這個信息即可。

分析A區域

dp[i]=(dis[j]dis[i]]a+dp[j])dp[i]=(\frac{dis[j]-dis[i]]}{a}+dp[j])

我們發現dp[i]只和dis[j]a+dp[j]\frac{dis[j]}{a}+dp[j]有關,其他都是常量,而這個在分析C區域中的線段樹已經維護,不需要再維護。

之後就倒着DP用線段樹轉移即可,轉移的時候要注意可以轉移的咖啡店的範圍,要注意邊界條件以及最初的pos就是爆int的。

代碼

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<time.h>
#include<math.h>
using namespace std;

//***********************IO**********************************
namespace FAST_IO
{
    #define BUF_SIZE 100000
    #define OUT_SIZE 100000
    bool IOerror=0;
    inline char nc()
    {
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
        if (p1==pend)
        {
            p1=buf;
            pend=buf+fread(buf,1,BUF_SIZE,stdin);
            if (pend==p1)
            {
                IOerror=1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch)
    {
        return ch==' '|ch=='\n'||ch=='\r'||ch=='\t';
    }
    inline void read(int &x)
    {
        bool sign=0;
        char ch=nc();
        x=0;
        for (; blank(ch); ch=nc());
        if (IOerror)return;
        if (ch=='-')sign=1,ch=nc();
        for (; ch>='0'&&ch<='9'; ch=nc())x=x*10+ch-'0';
        if (sign)x=-x;
    }
    #undef OUT_SIZE
    #undef BUF_SIZE
};
using namespace FAST_IO;
//************************************************************************

#define ok cout<<"OK"<<endl;
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl;
#define dbg3(x1,x2,x3) /*cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl;*/
#define print(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define pb push_back
#define Fi first
#define Se second
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define pil pair<int,ll>
#define pid pair<int,double>
#define pll pair<ll,ll>

const double eps = 1e-8;
const double PI = acos(-1.0);
const int Mod = 1000000007;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 5e5+10;
ll l,pos[maxn];
int a,b,t,r;
int n,pre[maxn];
double dp[maxn];
pii find_(ll L,ll R)
{
    int posl=lower_bound(pos+1,pos+1+n,L)-pos;
    int posr=upper_bound(pos+1,pos+1+n,R)-pos-1;
    return pii(posl,posr);
}
struct T
{
    int l,r,mid,id;
    double mn;
}tree[maxn<<2],tree2[maxn<<2];
void up(int rt)
{
    if(tree[rt<<1].mn<tree[rt<<1|1].mn)
    {
        tree[rt].id=tree[rt<<1].id;
        tree[rt].mn=tree[rt<<1].mn;
    }
    else
    {
        tree[rt].id=tree[rt<<1|1].id;
        tree[rt].mn=tree[rt<<1|1].mn;
    }
}
void build(int rt,int l,int r)
{
    tree[rt].l=l;
    tree[rt].r=r;
    if(l==r)
    {
        tree[rt].id=l;
        tree[rt].mn=dp[l]+1.0*pos[l]/a;
        return ;
    }
    int mid=tree[rt].mid=l+r>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    up(rt);
}
void update(int rt,int po,double val)
{
    if(tree[rt].l==tree[rt].r)
    {
        tree[rt].mn=val+1.0*pos[po]/a;
        return ;
    }
    if(po<=tree[rt].mid) update(rt<<1,po,val);
    else update(rt<<1|1,po,val);
    up(rt);
}
pid query(int rt,int l,int r)
{
    if(tree[rt].l>r||tree[rt].r<l) return pid(-1,1e18);
    if(tree[rt].l>=l&&tree[rt].r<=r) return pid(tree[rt].id,tree[rt].mn);
    pid ans=pid(-1,1e18);
    if(tree[rt].mid>=l)
    {
        pid tt = query(rt<<1,l,r);
        if(tt.Se<ans.Se) ans=tt;
    }
    if(tree[rt].mid<r)
    {
        pid tt= query(rt<<1|1,l,r);
        if(tt.Se<ans.Se) ans=tt;
    }
    return ans;
}



void up2(int rt)
{
    if(tree2[rt<<1].mn<tree2[rt<<1|1].mn)
    {
        tree2[rt].id=tree2[rt<<1].id;
        tree2[rt].mn=tree2[rt<<1].mn;
    }
    else
    {
        tree2[rt].id=tree2[rt<<1|1].id;
        tree2[rt].mn=tree2[rt<<1|1].mn;
    }
}
void build2(int rt,int l,int r)
{
    tree2[rt].l=l;
    tree2[rt].r=r;
    if(l==r)
    {
        tree2[rt].id=l;
        tree2[rt].mn=dp[l]+1.0*pos[l]/b;
        return ;
    }
    int mid=tree2[rt].mid=l+r>>1;
    build2(rt<<1,l,mid);
    build2(rt<<1|1,mid+1,r);
    up2(rt);
}
void update2(int rt,int po,double val)
{
    if(tree2[rt].l==tree2[rt].r)
    {
        tree2[rt].mn=val+1.0*pos[po]/b;
        return ;
    }
    if(po<=tree2[rt].mid) update2(rt<<1,po,val);
    else update2(rt<<1|1,po,val);
    up2(rt);
}
pid query2(int rt,int l,int r)
{
    if(tree2[rt].l>r||tree2[rt].r<l)
        return pid(-1,1e18);
    if(tree2[rt].l>=l&&tree2[rt].r<=r)
        return pid(tree2[rt].id,tree2[rt].mn);
    pid ans=pid(-1,1e18);
    if(tree2[rt].mid>=l)
    {
        pid tt = query2(rt<<1,l,r);
        if(tt.Se<ans.Se) ans=tt;
    }
    if(tree2[rt].mid<r)
    {
        pid tt= query2(rt<<1|1,l,r);
        if(tt.Se<ans.Se) ans=tt;
    }
    return ans;
}



int main()
{
    //freopen("A-2.in","r",stdin);
    scanf("%lld%d%d%d%d%d",&l,&a,&b,&t,&r,&n);
    ll LOW_ = a*t;
    ll FAST_ = b*r;
    for(int i=1;i<=n;i++) scanf("%lld",&pos[i]);
    for(int i=0;i<=n;i++)
    {
        if(pos[i]+LOW_>=l)
        {
            dp[i]=1.0*(l-pos[i])/a;
        }
        else if(pos[i]+LOW_+FAST_>=l)
        {
            dp[i]=1.0*(l-pos[i]-LOW_)/b+t;
        }
        else
        {
            dp[i]=1.0*(l-pos[i]-LOW_-FAST_)/a+t+r;
        }
        pre[i]=i;
    }
    if(n==0) return 0*puts("0");
    build(1,1,n);
    build2(1,1,n);
    for(int i=n-1;i>=1;i--)
    {
        ll l1=pos[i]+LOW_+FAST_,r1=l;
        pii t1=find_(l1,r1);
        double ans1 = -1.0*(pos[i]+LOW_+FAST_)/a+t+r;
        pid res1= query(1,t1.Fi,t1.Se);
        if(res1.Fi!=-1&&ans1+res1.Se<dp[i])
        {
            dp[i]=ans1+res1.Se;
            pre[i]=res1.Fi;
        }
        ll l2=pos[i]+LOW_,r2=pos[i]+LOW_+FAST_;
        pii t2=find_(l2,r2);
        double ans2 = -1.0*(pos[i]+LOW_)/b+t;
        pid res2= query2(1,t2.Fi,t2.Se);
        if(res2.Fi!=-1&&ans2+res2.Se<dp[i])
        {
            dp[i]=ans2+res2.Se;
            pre[i]=res2.Fi;
        }
        ll l3=pos[i],r3=pos[i]+LOW_;
        pii t3=find_(l3,r3);
        double ans3 = -1.0*(pos[i])/a;
        pid res3= query(1,t3.Fi,t3.Se);
        if(res3.Fi!=-1&&ans3+res3.Se<dp[i])
        {
            dp[i]=ans3+res3.Se;
            pre[i]=res3.Fi;
        }
        update(1,i,dp[i]);
        update2(1,i,dp[i]);
    }
    vector<int> ans;
    int pos=1;
    while(pre[pos]!=pos)
    {
        ans.push_back(pos-1);
        pos=pre[pos];
    }
    ans.push_back(pos-1);
    printf("%d\n",ans.size());
    for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章