跳转至

PIO18 单组_spj判断数组之和

入门通过率 55.1%python3样例通过牛客 AC

牛客原题  源码

讲解章节输入输出处理

一句话

构造 n 个正整数,使它们的和恰好为 m。

解题思路

这题考什么

输入形态:单组数据,一行两个整数。这是本系列唯一一道构造题: 答案不唯一,只要满足条件就行。

本题是 special judge(简称 spj,特殊评测:判定交给校验程序, 检查输出是否满足题目要求,而不是与标准答案逐字符对照。 见 solutions/_judge.json 里 PIO18 的 mode 为 spj)。 样例给的 1 2 3 只是众多合法答案之一,输出 1 1 4 同样通过。 这类题的思路是找一个最好写、最不容易出错的构造,而不是去猜标程写了什么。

最省事的构造:前 n - 1 个全填 1,把剩下的额度一次性塞进最后一个数, 也就是 m - (n - 1)。为什么它一定合法:题目保证 n <= m, 所以 m - (n - 1) >= n - (n - 1) = 1,最后一个数必然是正整数, 不会出现 0 或负数——这正是构造成立的全部依据,也是本题唯一需要证明的一步。

为什么这样写输出

n 最大 1e5,也就是最多要打十万个数。 ["1"] * (n - 1) 直接造出十万个字符串 "1" 的列表,元素全指向同一个字符串对象, 省掉了对十万个整数逐个调用 str() 的开销; 最后用 join 拼成一整行、一次 print 出去,只有一次输出调用。 若改成循环里逐个 print,就是十万次输出调用,而且会输出成十万行—— 题目要的是一行 n 个数,格式也不对。

数据规模与复杂度

1 <= n <= 1e5,n <= m <= 1e9。时间 O(n),空间 O(n)。 m 不超过 1e9,在 32 位范围内,本题不涉及大整数。

坑在哪

  1. 边界 n = 1:["1"] * 0 是空列表,输出只剩 str(m - 0),也就是 m 本身, 和为 m,正好符合要求,不需要特判。
  2. 题目要的是正整数,不能出现 0。用「前 n - 1 个填 0,最后填 m」这种构造 会直接判错——spj 只放宽「答案不唯一」,不放宽题目的取值约束。
  3. 元素个数必须恰好是 n 个。多一个少一个,校验程序照样不认。
  4. 最后一个数是 m - (n - 1) 而不是 m - n。填的是 n - 1 个 1, 减掉的自然也是 n - 1;写成 m - n 会让总和少 1。

样例复核

n = 3、m = 6 时,输出 1 1 4,和为 6,恰好 3 个正整数,符合要求; 与样例的 1 2 3 不同,但 spj 判定下同样通过。

参考实现

solutions/PIO18.py
1
2
3
4
n, m = map(int, input().split())
# 前 n-1 个填 1,余额全给最后一个;因题目保证 n <= m,故 m-(n-1) >= 1,必为正整数
# ["1"] * (n-1) 直接造字符串列表,省掉对 1e5 个整数逐个 str() 的开销
print(" ".join(["1"] * (n - 1) + [str(m - (n - 1))]))
[:octicons-arrow-left-16: PIO17](PIO17.md)