P14460 【MX-S10-T1】『FeOI-4』寻雾启示 题解

题目链接

我的博客

思路

这道题一看眼就是一个DP。

\(dp_i\) 表示走到 \(d=i\) 时需要的时间。枚举上一个状态,设上一个走到了 \(j(0 \leq j < i)\),那么我们可以通过以下步骤到达 \(i\)

  1. 首先回到 \(0\)
  2. \(0\) 处拿到 \(i-j\) 个铁锭(可能会等着)
  3. 跑步回 \(j\)
  4. \(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;
}
posted on 2025-11-10 08:57  _Liuliuliuliuliu  阅读(0)  评论(0)    收藏  举报