Description
在
一
个
一
维
坐
标
轴
上
,
一
个
人
要
从
0
位
置
走
到
位
置
l
。
在一个一维坐标轴上,一个人要从0位置走到位置l。
在一个一维坐标轴上,一个人要从0位置走到位置l。
他
的
默
认
速
度
为
a
,
他
希
望
在
最
短
时
间
到
达
位
置
l
他的默认速度为a,他希望在最短时间到达位置l
他的默认速度为a,他希望在最短时间到达位置l
幸
运
的
是
在
坐
标
轴
上
存
在
n
个
咖
啡
厅
,
他
可
以
在
任
意
咖
啡
厅
买
一
杯
咖
啡
幸运的是在坐标轴上存在n个咖啡厅,他可以在任意咖啡厅买一杯咖啡
幸运的是在坐标轴上存在n个咖啡厅,他可以在任意咖啡厅买一杯咖啡
他
需
要
t
秒
的
时
间
使
得
咖
啡
冷
却
(
冷
却
的
过
程
他
保
持
速
度
a
移
动
)
,
之
后
r
秒
他
在
喝
咖
啡
,
喝
咖
啡
时
的
速
度
为
b
。
(
b
>
a
)
他需要t秒的时间使得咖啡冷却(冷却的过程他保持速度a移动),之后r秒他在喝咖啡,喝咖啡时的速度为b。(b > a)
他需要t秒的时间使得咖啡冷却(冷却的过程他保持速度a移动),之后r秒他在喝咖啡,喝咖啡时的速度为b。(b>a)
他
有
且
仅
能
有
一
杯
咖
啡
在
手
上
,
但
是
他
可
以
把
没
喝
完
的
咖
啡
扔
了
,
在
新
的
咖
啡
店
重
新
购
买
。
他有且仅能有一杯咖啡在手上,但是他可以把没喝完的咖啡扔了,在新的咖啡店重新购买。
他有且仅能有一杯咖啡在手上,但是他可以把没喝完的咖啡扔了,在新的咖啡店重新购买。
问
怎
么
购
买
咖
啡
才
能
最
短
到
达
位
置
l
,
输
出
购
买
顺
序
。
问怎么购买咖啡才能最短到达位置l,输出购买顺序。
问怎么购买咖啡才能最短到达位置l,输出购买顺序。
Input
1
≤
l
≤
1
0
11
1\leq l \leq 10^{11}
1≤l≤1011
1
≤
a
<
b
≤
200
1\leq a < b \leq 200
1≤a<b≤200
0
≤
t
≤
300
0\leq t \leq 300
0≤t≤300
1
≤
r
≤
1200
1\leq r \leq 1200
1≤r≤1200
Output
1
购
买
次
数
1 购买次数
1购买次数
2
购
买
咖
啡
厅
编
号
2 购买咖啡厅编号
2购买咖啡厅编号
Solution
设
f
i
表
示
考
虑
前
i
个
咖
啡
厅
走
到
第
i
个
咖
啡
厅
的
最
短
时
间
设f_i表示考虑前i个咖啡厅走到第i个咖啡厅的最短时间
设fi表示考虑前i个咖啡厅走到第i个咖啡厅的最短时间
f
i
初
始
为
a
r
r
[
i
]
a
,
即
表
示
不
购
买
咖
啡
直
接
走
到
第
i
个
咖
啡
厅
位
置
。
f_i 初始为 \frac {arr[i]}{a},即表示不购买咖啡直接走到第i个咖啡厅位置。
fi初始为aarr[i],即表示不购买咖啡直接走到第i个咖啡厅位置。
然
后
有
f
i
=
m
i
n
(
f
j
+
c
o
s
t
(
j
,
i
)
)
(
0
<
j
<
i
)
然后有f_i = min(f_j+cost(j,i)) (0<j<i)
然后有fi=min(fj+cost(j,i))(0<j<i)
考
虑
在
第
j
个
咖
啡
厅
购
买
咖
啡
后
从
j
→
i
的
时
间
c
o
s
t
(
j
,
i
)
有
多
种
取
值
考虑在第j个咖啡厅购买咖啡后从j \to i的时间cost(j,i)有多种取值
考虑在第j个咖啡厅购买咖啡后从j→i的时间cost(j,i)有多种取值
设
l
i
m
1
=
t
∗
a
+
r
∗
b
:
设lim1 = t*a+r*b:
设lim1=t∗a+r∗b: 表示从冷却到喝完咖啡的最大距离
设
l
i
m
0
=
t
∗
a
:
设lim0 = t*a:
设lim0=t∗a: 表示咖啡刚好冷却完的距离。
c
o
s
t
(
j
,
i
)
分
为
一
下
三
种
情
况
cost(j,i) 分为一下三种情况
cost(j,i)分为一下三种情况
1.
a
r
r
[
i
]
−
a
r
r
[
j
]
≥
l
i
m
1
1.arr[i] - arr[j] \ge lim1
1.arr[i]−arr[j]≥lim1
c
o
s
t
(
j
,
i
)
=
a
r
r
[
i
]
−
a
r
r
[
j
]
−
l
i
m
1
a
+
t
+
r
\ \ \ \ \ \ \ \ cost(j,i) = \frac{arr[i]-arr[j]-lim1}{a}+t+r
cost(j,i)=aarr[i]−arr[j]−lim1+t+r
2.
l
i
m
0
≤
a
r
r
[
i
]
−
a
r
r
[
j
]
<
l
i
m
1
2.lim0 \leq arr[i]-arr[j]<lim1
2.lim0≤arr[i]−arr[j]<lim1
c
o
s
t
(
j
,
i
)
=
a
r
r
[
i
]
−
a
r
r
[
j
]
−
l
i
m
0
b
+
t
\ \ \ \ \ \ \ \ cost(j,i) = \frac{arr[i]-arr[j]-lim0}{b}+t
cost(j,i)=barr[i]−arr[j]−lim0+t
3.
a
r
r
[
i
]
−
a
r
r
[
j
]
<
l
i
m
0
3.arr[i]-arr[j]<lim0
3.arr[i]−arr[j]<lim0
c
o
s
t
(
j
,
i
)
=
a
r
r
[
i
]
−
a
r
r
[
j
]
a
\ \ \ \ \ \ \ \ cost(j,i) = \frac{arr[i]-arr[j]}{a}
cost(j,i)=aarr[i]−arr[j]
则
1.
a
r
r
[
i
]
−
a
r
r
[
j
]
≥
l
i
m
1
1.arr[i] - arr[j] \ge lim1
1.arr[i]−arr[j]≥lim1
f
i
=
f
j
+
c
o
s
t
(
j
,
i
)
=
f
j
−
a
r
r
[
j
]
a
+
a
r
r
[
i
]
−
l
i
m
1
a
+
t
+
r
\ \ \ \ \ \ \ \ f_i=f_j+cost(j,i) = \color {red} {f_j-\frac{arr[j]}{a}}+\frac{arr[i]-lim1}{a}+t+r
fi=fj+cost(j,i)=fj−aarr[j]+aarr[i]−lim1+t+r
对
于
a
r
r
[
j
]
≤
a
r
r
[
i
]
−
l
i
m
1
,
仅
需
要
对
满
足
条
件
的
j
维
护
f
j
−
a
r
r
[
j
]
a
的
最
小
值
即
可
,
不
需
要
优
先
队
列
。
\ \ \ \ \ \ \ \ 对于arr[j] \le arr[i]-lim1,仅需要对满足条件的j维护\color {red} {f_j-\frac{arr[j]}{a}}的最小值即可,不需要优先队列。
对于arr[j]≤arr[i]−lim1,仅需要对满足条件的j维护fj−aarr[j]的最小值即可,不需要优先队列。
2.
l
i
m
0
≤
a
r
r
[
i
]
−
a
r
r
[
j
]
<
l
i
m
1
2.lim0 \leq arr[i]-arr[j]<lim1
2.lim0≤arr[i]−arr[j]<lim1
f
i
=
f
j
+
c
o
s
t
(
j
,
i
)
=
f
j
−
a
r
r
[
j
]
b
+
a
r
r
[
i
]
−
l
i
m
0
a
+
t
\ \ \ \ \ \ \ \ f_i=f_j+cost(j,i) = \color {red} {f_j-\frac{arr[j]}{b}}+\frac{arr[i]-lim0}{a}+t
fi=fj+cost(j,i)=fj−barr[j]+aarr[i]−lim0+t
对
于
a
r
r
[
j
]
≤
a
r
r
[
i
]
−
l
i
m
0
时
将
f
j
−
a
r
r
[
j
]
b
加
入
优
先
队
列
。
\ \ \ \ \ \ \ \ 对于arr[j] \le arr[i]-lim0时将 \color {red} {f_j-\frac{arr[j]}{b}}加入优先队列。
对于arr[j]≤arr[i]−lim0时将fj−barr[j]加入优先队列。
对
于
a
r
r
[
j
]
≤
a
r
r
[
i
]
−
l
i
m
1
时
将
优
先
队
列
中
队
头
元
素
出
队
以
满
足
条
件
a
r
r
[
j
]
>
a
r
r
[
i
]
−
l
i
m
1
。
\ \ \ \ \ \ \ \ 对于arr[j] \le arr[i]-lim1时将 优先队列中队头元素出队以满足条件arr[j] > arr[i]-lim1。
对于arr[j]≤arr[i]−lim1时将优先队列中队头元素出队以满足条件arr[j]>arr[i]−lim1。
3.
由
于
最
优
性
,
第
三
种
是
前
两
种
的
子
集
,
即
最
优
值
不
会
出
现
在
第
三
种
情
况
下
。
3.由于最优性,第三种是前两种的子集,即最优值不会出现在第三种情况下。
3.由于最优性,第三种是前两种的子集,即最优值不会出现在第三种情况下。
Codes
O
n
e
One
One
三
个
优
先
队
列
模
拟
,
其
实
只
用
一
个
就
够
了
,
最
后
的
输
出
格
式
让
我
对
拍
了
一
上
午
。
明
明
能
一
遍
A
C
的
。
三个优先队列模拟,其实只用一个就够了,最后的输出格式让我对拍了一上午。明明能一遍AC的。
三个优先队列模拟,其实只用一个就够了,最后的输出格式让我对拍了一上午。明明能一遍AC的。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,double> node;
const double inf = 1ll<<62;
const int maxn = 5e5+10;
ll arr[maxn],l,a,b,t,r;
int n,ans[maxn],last[maxn],cnt;
double dp[maxn];
node qu1[maxn],qu2[maxn],qu3[maxn];
int main()
{
while(~scanf("%lld%lld%lld%lld%lld",&l,&a,&b,&t,&r)) {
scanf("%d",&n);
cnt = 0;
memset(dp,0,sizeof(dp));
memset(last,0,sizeof(last));
for(int i=1;i<=n;i++) scanf("%lld",&arr[i]);arr[0] = 0;
arr[++n] = l;
ll x = a*t,y = a*t+b*r;
int h1 = 1,t1 = 0,h2 = 1,t2 = 0,h3 = 1,t3 = 0;
int pos1 = 1,pos2 = 1;
for(int i=1;i<=n;i++) {
while(i > pos1 && arr[pos1] + x < arr[i]) {
double it2 = dp[pos1]-1.0*arr[pos1]/b;
while(h2 <= t2 && qu2[t2].second >= it2) t2--;
qu2[++t2] = make_pair(pos1,it2);
pos1++;
}
while(i > pos2 && arr[pos2] + y < arr[i]) {
double it2 = dp[pos2]-1.0*arr[pos2]/a;
while(h3 <= t3 && qu3[t3].second >= it2) t3--;
qu3[++t3] = make_pair(pos2,it2);
pos2++;
}
//printf("1\n");
if(i == 1) dp[1] = 1.0*arr[i] / a;
else {
dp[i] = inf;
while(h1 <= t1 && arr[qu1[h1].first]+x < arr[i]) h1++;
if(h1 <= t1) {
if(dp[i] > 1.0*arr[i]/a+qu1[h1].second) {
dp[i] = 1.0*arr[i]/a+qu1[h1].second;
last[i] = qu1[h1].first;
}
}
while(h2 <= t2 && arr[qu2[h2].first]+y < arr[i]) h2++;
if(h2 <= t2) {
if(dp[i] > 1.0*(arr[i]-x)/b+t+qu2[h2].second) {
dp[i] = 1.0*(arr[i]-x)/b+t+qu2[h2].second;
last[i] = qu2[h2].first;
}
}
if(h3 <= t3) {
if(dp[i] > 1.0*(arr[i]-y)/a+t+r+qu3[h3].second) {
dp[i] = 1.0*(arr[i]-y)/a+t+r+qu3[h3].second;
last[i] = qu3[h3].first;
}
}
}
double it1 = dp[i]-1.0*arr[i]/a;
while(h1 <= t1 && qu1[t1].second >= it1) t1--;
qu1[++t1] = make_pair(i,it1);
}
int cur = n;
while(last[cur]) {
ans[cnt++] = last[cur];
cur = last[cur];
}
printf("%d\n",cnt);
for(int i=cnt-1;i>=0;i--) printf("%d ",ans[i]-1);
// 写自闭了 MDZZ
// for(int i=cnt-1;i>0;i--) printf("%d ",ans[i]-1);printf("%d\n",ans[0]-1);
}
return 0;
}
T
w
o
Two
Two
更简单明了的写法
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5+10;
const double inf = 1e20;
typedef long long ll;
typedef pair<int,double> Node;
Node qu[maxn];
int n,path[maxn],cnt,ans[maxn];
ll L,a,b,t,r,arr[maxn];
double dp[maxn];
int main()
{
while(~scanf("%lld%lld%lld%lld%lld",&L,&a,&b,&t,&r)){
memset(path,0,sizeof(path));cnt = 0;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld",&arr[i]);arr[++n]=L;
ll lim0 = a*t,lim1 = a*t+b*r;
double dp0 = inf;
int id0=0,head=1,tail=0;
for(int i=1,j=1,k=1;i<=n;i++) {
dp[i] = 1.0*arr[i]/a;
/// arr[i] - arr[j] >= lim1
while(j < i && arr[i] - arr[j] >= lim1) {
double tmp = dp[j] - 1.0*arr[j] / a;
if(tmp < dp0) {
dp0 = tmp;
id0 = j;
}
j++;
}
if(id0) {
double tmp = dp0 + t + r + 1.0*(arr[i]-lim1) / a;
if(tmp < dp[i]) {
dp[i] = tmp;
path[i] = id0;
}
}
/// lim0<= arr[i] - arr[j] <lim1
while(k < i && arr[i] - arr[k] >= lim0) {
double tmp = dp[k] - 1.0*arr[k]/b;
while(head <= tail && qu[tail].second > tmp) tail--;//
qu[++tail] = make_pair(k,tmp);
k++;
}
while(head<=tail && arr[i]-arr[qu[head].first] >= lim1) head++;
if(head <= tail) {
double tmp = qu[head].second+t+1.0*(arr[i]-lim0)/b;
if(tmp < dp[i]) {
dp[i] = tmp;
path[i] = qu[head].first;
}
}
}
int id = n;
while(path[id]) {
ans[++cnt] = path[id];
id = path[id];
}
printf("%d\n",cnt);
for(int i=cnt;i;i--) {
if(i == 1) printf("%d\n",ans[i]-1);
else printf("%d ",ans[i]-1);
}
// 写自闭了 MDZZ
// for(int i=cnt;i>1;i--) printf("%d ",ans[i]-1);
// printf("%d\n",ans[1]);
}
return 0;
}