P14460 【MX-S10-T1】『FeOI-4』寻雾启示 题解
思路
这道题一看眼就是一个DP。
设 \(dp_i\) 表示走到 \(d=i\) 时需要的时间。枚举上一个状态,设上一个走到了 \(j(0 \leq j < i)\),那么我们可以通过以下步骤到达 \(i\)。
- 首先回到 \(0\)。
- 在 \(0\) 处拿到 \(i-j\) 个铁锭(可能会等着)
- 跑步回 \(j\)
- 从 \(j\) 铺路到 \(i\)。
于是我们就有了转移方程
\[f[i]=\min_{j=0}^{i-1} \max(f_j+t_2 \times j,i \times k)+t_2 \times j +t_1 \times (i-j)
\]
时间复杂度 \(O(Tm^2)\)
考虑优化。我们发现 \(f_i\) 是单调的。于是我们得到,\(f_j+t_2 \times j\) 也是单调的。所以我们可以找到一个最大的 \(j\) 满足 \(f_j + t_2 \times j < i \times k\)。这里用二分实现优化。
最终时间复杂度 \(O(T m \log m)\)
代码
const int N=1e5+10;
int T,m,k,t1,t2;
int f[N];
void solve(){
m=Read();k=Read();t1=Read();t2=Read();
for(int i=1;i<=m;i++) f[i]=INF;
f[0]=0;
if(t1<=t2){
for(int i=1;i<=m;i++){
printf("%lld ",i*t1+i*k);
}
puts("");
return ;
}
for(int i=1;i<=m;i++){
int l=0,r=i-1;
while(l<r){
int mid=(l+r+1)>>1;
if(f[mid]+mid*t2<=i*k) l=mid;
else r=mid-1;
}
f[i]=min(f[i],i*k+l*t2+(i-l)*t1);
if(l<i-1) l++,f[i]=min(f[i],l*t2+(i-l)*t1+max(i*k,f[l]+l*t2));
}
for(int i=1;i<=m;i++) printf("%lld ",f[i]);
puts("");
}
signed main(){
T=Read();
while(T--){
solve();
}
return 0;
}
浙公网安备 33010602011771号