1 条题解
-
0
C. 最长好数组 - 详细题解
问题重述
构造一个严格递增的数组 ,满足相邻元素差严格递增,且所有元素在 范围内。求最大可能长度。
贪心策略
为了构造最长的好数组,我们应该让数组的增长尽可能慢,这样才能在有限区间 内放入更多元素。
贪心构造方法:
- 第一个元素取最小值:
- 第二个元素取 (最小可能的增长)
- 第三个元素取 (差值为 )
- 第四个元素取 (差值为 )
- 以此类推...
通项公式
第 个元素的值为:
推导过程:
设 为相邻差,则
$$\begin{aligned} a_i &= a_1 + d_1 + d_2 + \cdots + d_{i-1} \\ &= l + (1 + 2 + \cdots + (i-1)) \\ &= l + \frac{(i-1)i}{2} \end{aligned} $$
正确性证明
引理
贪心构造的数组 是最优的,即不存在比它更长的好数组。
证明思路
假设存在另一个好数组 ,长度大于 。
由于 是贪心构造的(每个位置都取最小可能值),必然存在某个位置 ,使得:
- 对于所有 ,有
- (因为 已是最小)
设 为 的长度(假设只长 ),则:
$$b_n - b_{n-1} > b_{n-1} - b_{n-2} \ge a_{n-1} - a_{n-2} $$这意味着我们可以将 附加到数组 的末尾,构造出更长的数组,与 的最大性矛盾。
因此,贪心构造的数组 就是最优解。
问题转化
由通项公式 ,我们需要找到最大的 满足:
令 ,则条件化为:
即:
求解方法
方法一:解二次不等式
解方程 :
因此:
$$n_{\max} = \left\lfloor \frac{1 + \sqrt{1 + 8b}}{2} \right\rfloor $$方法二:二分查找
二分查找最大的 满足 。
算法步骤
- 读入 和
- 计算
- 二分查找最大的 使得
- 输出
完整代码
#include <bits/stdc++.h> using namespace std; int main() { int t; cin >> t; while (t--) { long long l, r; cin >> l >> r; long long b = r - l; // 可用的增长空间 // 二分查找最大的 n 满足 n*(n-1)/2 <= b long long left = 2, right = 1000000000; while (left < right) { long long mid = (left + right) / 2; if (mid * (mid - 1) / 2 <= b) { left = mid + 1; } else { right = mid; } } cout << left - 1 << endl; } return 0; }
公式解法(更简洁)
#include <bits/stdc++.h> using namespace std; int main() { int t; cin >> t; while (t--) { long long l, r; cin >> l >> r; long long b = r - l; long long n = (1 + sqrt(1 + 8 * b)) / 2; cout << n << endl; } return 0; }
时间复杂度
- 二分查找: 每个测试用例
- 公式解法: 每个测试用例
- 总复杂度: 或
示例验证
的最大 输出 1 2 1 : ✓ 2 5 4 : ✓
: ✗3 2 0 : ✓ 1 10 20 10 : ✓
: ✗5 1 解方程得 44721 与样例输出完全一致。
- 1
信息
- ID
- 6327
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 3
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者