题解:P11791 [JOI 2017 Final] 准高速电车 / Semiexpress
约定:以下称快车为高速电车,中车为准高速电车,慢车为普通列车。
本人语文不好,读错了两次题:
- 只能从
i 走到i+1 ,不能反着走。 - 快车和中车都是两个站(不管是否停靠)之间要走
B /C 分钟,不是两个停靠的站之间。
小清新贪心题。
Observation 1:对于每个站,到达它的最优方式永远是先坐快车到前面离它最近的快车站,再坐中车到前面离它最近的中车站,再坐慢车。
Prove 1:因为
Observation 2:每两个快车站间独立,即在
Prove 2:根据 Observation 1,如果需要达到快车站
Observation 3:有一种贪心策略:对于每两个快车站间,从前往后放中车站,每次在第一个无法达到到的点处放置中车站,直到 放了还是无法达到 或 这两个快车站间已经放了
Prove 3:显然我们可以看作从前往后放中车站。设放了
Observation 4:根据 Observation 3,现在我们的问题就是在每两个快车站之间放多少个中车站。我们转化为这么一个问题:设
Prove 4:简单的转化,显然。
现在有一个简单的
Observation 5:对于一个
Prove 5:距离快车站
Observation 6:可以把取一个前缀的条件去掉。
Prove 6:根据 Observation 5,
Observation 7:又可以转化为把
Prove 7:不同段之间并没有外加的限制。
现在可以直接排序后取前
int n,m,k,a,b,c,as=-1,p[N]; ll t;
priority_queue<int,vi,greater<int>> q;
void QwQ() {
n=rd(),m=rd(),k=rd()-m,a=rd(),b=rd(),c=rd(),t=rdll();
for(int i=1;i<=m;i++) p[i]=rd();
for(int i=1;i<=m;i++) {
if(1ll*(p[i]-1)*b>t) break;
if(i==m) {as++; break;}
as+=min((ll)p[i+1]-p[i],(t-1ll*(p[i]-1)*b)/a+1); int ct=0;
for(ll x=p[i]+(t-1ll*(p[i]-1)*b)/a+1,y=t-1ll*(p[i]-1)*b-(x-p[i])*c,nx;y>=0&&x<p[i+1];y-=(nx-x)*c,x=nx) {
nx=min((ll)p[i+1],x+y/a+1),q.push(nx-x);
if(++ct==k) break;
}
for(;q.size()>k;) q.pop();
}
for(;q.size();) as+=q.top(),q.pop();
wr(as,"\n");
}