文章目录

‹
›

T1 称重(weight)题解

T1 称重(weight)题解

考场策略:第一题数据范围 \(n \le 2\times10^5\),应优先尝试贪心。如果一时想不到正确贪心,可以先写DP拿 65 分,再根据特殊性质往上加。

题面

有 \(n\) 件物品排成一行,每件重量为 \([0,H]\) 内的整数。有 \(n-1\) 条称重记录 \(b_i\),表示第 \(i\) 件和第 \(i+1\) 件的重量之和为 \(b_i\)。记录可能矛盾,可以删除一些记录,使得剩下的记录都能成立。求最少删除多少条记录。

思路

核心观察:如果连续的一段记录都保留,那么每件物品的可行重量构成一个连续区间。

假设当前物品的可行重量是区间 \([L, R]\),加入记录 \(b_i\) 后,下一件物品的重量为 \(b_i - w_i\),所以可行区间变为 \([b_i-R, b_i-L]\),再与 \([0, H]\) 取交集:

\(L' = \max(0, b_i - R), \quad R' = \min(H, b_i - L)\)

如果 \(L' > R'\),说明这条记录无法与前面的记录同时保留,必须删除。

贪心策略:从左到右扫描,维护当前连续段的可行重量区间。遇到矛盾就删除当前记录(答案 +1),并重置区间为 \([0, H]\),从下一件物品开始新的一段。

正确性证明(调整法 ( 邻项微扰 )):任取一个最优方案,考虑第一段从 \(s\) 开始,\(b_t\) 是第一个出现矛盾的位置。原方案在 \([s, t]\) 中至少删一条记录。我们可以把这段内的删除全部替换成只删 \(b_t\):

  • 左侧:\(b_s, \dots, b_{t-1}\) 全部保留(因为 \(t\) 是第一个矛盾位置,它们一定相容)
  • 右侧:删除 \(b_t\) 后,物品 \(t+1\) 与左侧断开约束,原方案右侧仍然成立

这样调整后删除数不会增加,且方案仍然合法。因此存在一个最优解,每次删除都发生在第一次矛盾的位置,这正是贪心算法的行为。

AC code

#include <bits/stdc++.h>
using namespace std;

using ll = long long;

const int N = 2e5 + 5;
const ll INF = 1e18;

ll n, H;
ll b[N];

int main () {
	freopen("weight.in", "r", stdin);
	freopen("weight.out", "w", stdout);
	
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	cin >> n >> H;
	
	ll L = 0, R = H;
	ll ans = 0;
	
	for (int i = 1; i < n; i ++) {
		ll b; cin >> b;
		
		ll nL = max(0ll, b - R);
		ll nR = min(H, b - L);
		if (nL <= nR) {
			L = nL;
			R = nR;
		}
		else {
			ans ++;
			L = 0;
			R = H;
		}
	}
	
	cout << ans << '\n';
	
	return 0;
}

复杂度分析

  • 时间复杂度:\(O(n)\),每条记录只处理一次

考场思路与得分路径

得分 算法 适用范围
10 分 枚举所有重量 \(n \le 5, H = 1\)
20 分 枚举删法 + 区间判定 \(n \le 20\)
30 分 重量 DP \(O(nH^2)\) \(n, H \le 200\)
40 分 重量 DP 优化 \(O(nH)\) \(n, H \le 2000\)
65 分 分段 DP \(O(n^2)\) \(n \le 3000\)
70 分 + 特判 H=1 \(n \le 2\times10^5, H=1\)
75 分 + 特判 H≤2 \(n \le 2\times10^5, H\le2\)
100 分 可行区间 + 贪心 全部数据
posted @ 2026-10-02 18:47  lvwangshu  阅读(13)  评论(1)    收藏  举报