LuoguP7593 凑数 题解

Content

给定 \(n\) 个整数 \(1,2,\dots,n\),请问是否能从这 \(n\) 个数中恰好选 \(k\) 个数,使得这 \(k\) 个数的和为 \(s\)

数据范围:\(t\) 组数据,\(1\leqslant t\leqslant 10^3\)\(1\leqslant k\leqslant n\leqslant 10^9\)\(1\leqslant s\leqslant 10^{18}\)

Solution

我们都知道,从 \(1\)\(n\) 中选出 \(k\) 个数,最小和是 \(1\sim k\) 的和,最大和是 \(n-k+1\sim n\) 的和,而在此之间的所有的整数和都能够通过最小和和最大和当中的某些数进行加减得到,比如说 \(1\sim 5\) 中选出 \(3\) 个数,最小和是 \(6\),最大和是 \(12\),那么可以构造出如下的整数和的方案:

  • 选出的数的集合为 \(\{1,2,3\}\),总和为 \(6\)
  • 选出的数的集合为 \(\{1,2,4\}\),总和为 \(7\)
  • 选出的数的集合为 \(\{1,2,5\}\),总和为 \(8\)
  • 选出的数的集合为 \(\{1,3,5\}\),总和为 \(9\)
  • 选出的数的集合为 \(\{1,4,5\}\),总和为 \(10\)
  • 选出的数的集合为 \(\{2,4,5\}\),总和为 \(11\)
  • 选出的数的集合为 \(\{3,4,5\}\),总和为 \(12\)

其实这也给出了一种构造出从 \(1\)\(n\) 中选出 \(k\) 个数和为 \(s\) 的一种方案:

  • 首先,先选出 \(1\sim k\)
  • 然后,从最后一个数(第 \(k\) 个数)开始往前推,如果当前到了第 \(i\) 个数,直接加到 \(n-k+i\),再根据是否超过了 \(s\) 进行判断。如果当前和 \(\geqslant s\),那么将当前数减回去到刚好使和等于 \(s\),否则继续往前推。
  • 依此下去,就能够构造出一种满足题目要求的方案。

因此我们先算出 \(s_{\min}=\sum\limits_{i=1}^k i=\dfrac{k(k+1)}2\)\(s_{\max}=\sum\limits_{i=1}^kn-k+i=\dfrac{(2n-k+1)k}2\),然后再拿 \(s_{\min},s_{\max}\)\(s\) 进行比较。如果 \(s_{\min}\leqslant s\leqslant s_{\max}\),那么显然能够恰好选出和为 \(s\)\(k\) 个数,否则就不行。

Code

int main() {
	MT {
		ll n = Rll, k = Rll, s = Rll;
		((2 * n - k + 1) * k / 2 < s || (1 + k) * k / 2 > s) ? No : Yes;
	}
    return 0;
}
posted @ 2021-12-15 22:07  Eason_AC  阅读(46)  评论(0)    收藏  举报