https://codeforces.com/gym/101572/problem/A
100000 100 138 60 300
5
5000 20000 50000 55000 75000
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这个点喝咖啡之后,一共有以下三个区域。
设当前点的位置为 p o s [ i ] pos[i] pos[i],选择的咖啡店的位置为 p o s [ j ] pos[j] pos[j]
设 d p [ i ] dp[i] dp[i]为从i咖啡店走到终点的最短时间。
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]−a∗t−b∗r+dp[j]+t+r)
我们发现dp[i]只和 d i s [ j ] a + d p [ j ] \frac{dis[j]}{a}+dp[j] adis[j]+dp[j]有关,其他都是常量,所以我们只要用一棵线段树存储这个信息即可。
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]−a∗t+t+dp[j])
我们发现dp[j]只和 d i s [ j ] b + d p [ j ] \frac{dis[j]}{b}+dp[j] bdis[j]+dp[j]有关,其他都是常量,所以我们只要用一棵线段树存储这个信息即可。
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;
}