[结论题] [dp] [单调队列优化] P2300 合并神犇

posted on 2024-03-11 05:40:12 | under | source

前言:周六和 lsy 找到了 P2300 合并神犇这道题,做完后才发现很像 P5665 划分,这两题的解的合法性定义都是完全一样的,只是答案不同。

结论部分

上数学课时手推的,如有不严谨之处请指出。

首先定义 \(f_i\) 表示前 \(i\) 个数的最小合并次数,\(lst_i\) 所有情况下合并后结尾元素最小值。

  • 引理: \(\forall i\in [2,n],0\le f_i-f_{i-1}\le 1\)

证明:对于上界,\(f_i\) 可以由 \(f_{i-1}+1\) 得到,即将 \(lst_{i-1}\)\(a_i\) 合并。

再证下界。假如 \(lst_i=a_i\),则 \(f_{i-1}\) 可以由 \(f_i-1\) 得到,去掉 \(a_i\) 即可。反之,将 \(a_i\) 去掉,再将末尾元素与倒数第二个元素合并,\(f_{i-1}=f_i-1+1=f_i\)。证毕。

  • 结论:\(a_1...a_i\) 的答案必定满足 \(lst_i\) 最小。

证明:反证法。设 \(f_i\) 取最小值时,结尾元素(合并后)\(>lst_i\)。令该情况下结尾元素由 \(a_j...a_i\) 合并得到,\(lst_i\)\(a_k...a_i\) 合并得到。由于 \(\forall a_i>0\),所以 \(j<k\)

同时,在此假设下 \(lst_i\) 对应的答案 \(ans\prime>f_i\)。我们知道 \(f_i=f_j+i-j-1\)\(ans\prime=f_k+i-k-1\),代入上式并化简得 \(f_k-f_j>k-j\)。由引理知 \(i\) 每增长 \(1\)\(f_i\) 至多增长 \(1\),所以 \(f_k-f_j\le k-j\)。矛盾,假设不成立,故原结论正确,证毕。

dp 部分

维护 \(f_i\)\(lst_i\),定义与上面的相同。暴力转移是 \(O(n^2)\) 的,需要优化。

观察暴力转移代码,\(s\)\(a\) 前缀和:

for(int j = 0; j <= i - 1; ++j){
	if(lst[j] <= s[i] - s[j] && f[j] + (i - j - 1) <= f[i]){
		f[i] = f[j] + (i - j - 1);
		lst[i] = min(lst[i], s[i] - s[j]);
	}
}

由于转移不存在 \(F(i)\times G(j)\) 的形式,故考虑单调队列优化。

易发现 \(s\) 单调递增,于是对于决策的限制是不断放宽的。

还可发现对于 \(j<k\),必有 \(f_j+(i-j-1)\ge f_k+(i-k-1)\)。于是最优决策点 \(j\) 不会左移。

然后要使 \(s_i-s_j\) 最小,即 \(j\) 最大。可以想到维护下标递增、\(lst\) 递增的单调队列。每次从头开始找到最后一个满足 \(lst_k+s_k\le s_i\)\(k\) 作为最优决策点,\(k\) 之前的全都踢出(决策点不左移);然后从队尾开始,将 \(lst_p\ge lst_i\)\(p\) 全部踢出,将 \(i\) 入队(\(i\) 在答案上比 \(p\) 更优、也更容易满足限制)。

代码

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

#define int long long
const int N = 2e5 + 5;
int n, a[N], f[N], lst[N], q[N], l, r;

signed main(){
	cin >> n;
	for(int i = 1; i <= n; ++i) scanf("%lld", &a[i]), a[i] += a[i - 1];
	q[l = r = 1] = 0;
	for(int i = 1; i <= n; ++i){
		while(l + 1 <= r && lst[q[l + 1]] + a[q[l + 1]] <= a[i]) ++l;
		f[i] = f[q[l]] + (i - q[l] - 1), lst[i] = a[i] - a[q[l]];
		while(l <= r && lst[q[r]] + a[q[r]] >= lst[i] + a[i]) --r;
		q[++r] = i;
	}
	cout << f[n];
	return 0;
}

总结

这两题都先从性质入手,P2300 通过数学推理得出结论,P5665 通过贪心感性猜出性质,并通过打表得到一定验证。使得状态被优化至 \(O(n)\) 的级别。

posted @ 2026-01-12 20:15  Zwi  阅读(2)  评论(0)    收藏  举报