【NCPC2017-2018-gym101572-A.Airport Coffee 】 线段树+分类讨论DP

Airport Coffee

题目链接:

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

Description

【NCPC2017-2018-gym101572-A.Airport Coffee 】 线段树+分类讨论DP_第1张图片

Input

【NCPC2017-2018-gym101572-A.Airport Coffee 】 线段树+分类讨论DP_第2张图片

Output

【NCPC2017-2018-gym101572-A.Airport Coffee 】 线段树+分类讨论DP_第3张图片

Sample Input

100000 100 138 60 300
5
5000 20000 50000 55000 75000

Sample Output

2
0 3

题意

0 0 0这个位置出发走到 l l l这个位置,速度为 a a a,路上有 n n n个咖啡店,可以选择在某个咖啡店买或者不买咖啡,如果选择买咖啡,需要用 t t t的时间等咖啡变凉,在这 t t t的时间内速度为 a a a,之后可以喝咖啡走 r r r时间的路,在这期间速度为 b b b。拥有咖啡的同时仍然可以买咖啡。问走到 l l l这个位置的最短时间。

题解

首先这道题要考虑倒着做,因为最后一个咖啡店选择喝/不喝咖啡到达l的时间是确定的,我们只要倒着推就可以。

之后我们考虑从i这个点到达终点的最优值一定可以从某个j咖啡店转移过来,我们怎么保证最优的。

首先分析一下在i这个点喝咖啡之后,一共有以下三个区域。

【NCPC2017-2018-gym101572-A.Airport Coffee 】 线段树+分类讨论DP_第4张图片
首先通过二分找出所有在每个区域中的最左咖啡店和最右咖啡店。

设当前点的位置为 p o s [ i ] pos[i] pos[i],选择的咖啡店的位置为 p o s [ j ] pos[j] pos[j]

d p [ i ] dp[i] dp[i]为从i咖啡店走到终点的最短时间。

分析C区域

d p [ i ] = ( d i s [ j ] − d i s [ i ] − a ∗ t − b ∗ r a + d p [ j ] + t + r ) dp[i] = (\frac{dis[j]-dis[i]-a*t-b*r}{a}+dp[j]+t+r) dp[i]=(adis[j]dis[i]atbr+dp[j]+t+r)

我们发现dp[i]只和 d i s [ j ] a + d p [ j ] \frac{dis[j]}{a}+dp[j] adis[j]+dp[j]有关,其他都是常量,所以我们只要用一棵线段树存储这个信息即可。

分析B区域

d p [ i ] = ( d i s [ j ] − d i s [ i ] − a ∗ t b + t + d p [ j ] ) dp[i]=(\frac{dis[j]-dis[i]-a*t}{b}+t+dp[j]) dp[i]=(bdis[j]dis[i]at+t+dp[j])

我们发现dp[j]只和 d i s [ j ] b + d p [ j ] \frac{dis[j]}{b}+dp[j] bdis[j]+dp[j]有关,其他都是常量,所以我们只要用一棵线段树存储这个信息即可。

分析A区域

d p [ i ] = ( d i s [ j ] − d i s [ i ] ] a + d p [ j ] ) dp[i]=(\frac{dis[j]-dis[i]]}{a}+dp[j]) dp[i]=(adis[j]dis[i]]+dp[j])

我们发现dp[i]只和 d i s [ j ] a + d p [ j ] \frac{dis[j]}{a}+dp[j] adis[j]+dp[j]有关,其他都是常量,而这个在分析C区域中的线段树已经维护,不需要再维护。

之后就倒着DP用线段树转移即可,转移的时候要注意可以转移的咖啡店的范围,要注意边界条件以及最初的pos就是爆int的。

代码

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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"<
#define dbg(x) cout<<#x<<" = "<
#define dbg2(x1,x2) cout<<#x1<<" = "<#define dbg3(x1,x2,x3) /*cout<<#x1<<" = "<#define print(a,n) for(int i=1;i<=n;i++) cout<
#define pb push_back
#define Fi first
#define Se second
#define ll long long
#define ull unsigned long long
#define pii pair
#define pil pair
#define pid pair
#define pll pair

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;
}


你可能感兴趣的:(Codeforces,DP,线段树)