题解:P16353 「Diligent-OI R3 A」说好不哭

· · 题解

1. 题意

输入三个数 n,x,y,判断是否存在一个长度为 n 的整数序列满足最大非空子段和为 x,最小非空子段和为 y

2. 分析

比较入门的构造类题目。

n 的大小以及 x, y 的符号进行分类。

(1)当 n = 1

序列只有一个元素 a_1。此时最大非空子段和与最小非空子段和都等于 a_1

此时充要条件直接就是 x=y

(2)当 n \ge 2

::::info{open} 本部分分析少量借助 Qwen 3.6 完成。 ::::

要判断是否存在这样的子段,根据 x, y 的符号分为三种情况。

此时令序列为 $\{x, y, 0, 0, \dots, 0\}$。如此一来由于 $y \le 0 \le x$,任意子段和必然落在 $[y, x]$ 区间内。包含 $x$ 的子段最大值为 $x$,包含 $y$ 的子段最小值为 $y$。中间的 $0$ 不会改变最值。 $x \ge y\ge 0$: 此时所有子段和均为正,说明序列中**不能有非正数**(否则会出现 $\le 0$ 的子段和,与最小值为正矛盾)。对于全正序列: - 最大子段和一定是**整个序列的总和**(加正数只会变大)。 - 最小子段和一定是**最小的单个元素**(任意更长子段和都大于其中任一元素)。 - 因此必须满足:总和为 $x$,且每个元素 $\ge y$。即 $x \ge n \cdot y$。 此时的充要条件是 $x\ge ny$。构造方法是 $a_1 = x - (n-1)y$,其余 $a_i = y$。由条件知 $a_1 \ge y$,所有元素为正,满足题意。 $x < 0$(此时必有 $y \le x < 0$,全负情况): 此时所有子段和均为负,说明序列中**不能有非负数**。 对于全负序列,最小子段和一定是**整个序列的总和**(加负数只会变小),最大子段和一定是**最大的单个元素**(即绝对值最小的负数)。 因此必须满足:总和为 $y$,且每个元素 $\le x$。即 $y \le n \cdot x$。 此时的充要条件是 $y\le nx$。构造方法是 $a_1 = y - (n-1)x$,其余 $a_i = x$。由条件知 $a_1 \le x$,所有元素为负,满足题意。 汇总以上结果,我们直接上伪代码。 ::::info[伪代码]{open} 对每组数据 $(n, x, y)$: 1. 若 `n == 1`: - 判断是不是 `x == y` 2. 若 `n >= 2`: - 若 `x >= 0 and y <= 0` - 直接输出 `YES` - 若 `x >= 0 and y > 0` - 判断 `x >= n * y` - 若 `x < 0` - 判断 `y <= n * x` :::: 最后单组数据直接就是 $O(1)$ 的常数复杂度了。 ## 3. 代码 ::::success[C#] ```csharp using System; class P16353 { static void Solve() { string line = Console.ReadLine(); int T = Convert.ToInt32(line); while (T-- > 0) { string[] inputs = Console.ReadLine().Split(); long n = long.Parse(inputs[0]); long x = long.Parse(inputs[1]); long y = long.Parse(inputs[2]); bool ok = false; if (n == 1) { ok = (x == y); } else { if (x >= 0 && y <= 0) { ok = true; } else if (x >= 0 && y > 0) { ok = (x >= n * y); } else { ok = (y <= n * x); } } Console.WriteLine(ok ? "YES" : "NO"); } } static void Main() { Solve(); } } ``` :::: ::::success[C++] ```cpp #include <bits/stdc++.h> using namespace std; using ll = long long; void solve() { int T; if (!(cin >> T)) return; while (T--) { ll n, x, y; cin >> n >> x >> y; bool ok = false; if (n == 1) { ok = (x == y); } else { if (x >= 0 && y <= 0) { ok = true; } else if (x >= 0 && y > 0) { ok = (x >= n * y); } else { ok = (y <= n * x); } } cout << (ok ? "YES\n" : "NO\n"); } } int main() { solve(); return 0; } ``` ::::