小红的构造数组
C++代码
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n;
long long k, x;
cin >> n >> k >> x;
long long s = ((long long)n) * (n + 1) / 2;
if (s > x || n > k) {
cout << "-1" << endl;
} else {
vector<long long> arr(n + 1);
for (int i = 1; i <= n; i++) {
arr[i] = i;
}
x -= s;
long long d = x / n;
long long v = x % n;
for (int i = 1; i <= n; i++) {
arr[i] += d;
if (n - i < v) {
arr[i]++;
}
}
// 对数组进行最后的check,保证每个元素都小于等于k
bool ok = true;
for (int i = 1; i <= n; i++) {
if (arr[i] > k) ok = false;
}
if (!ok) cout << "-1" << endl;
else {
for(int i = 1; i <= n; i++){
cout << arr[i] << (i < n ? ' ' : '\n');
}
}
}
return 0;
}
思路:
先安排1~n填充,即arr[i] = i
那这样还剩余:left = x - (n+1)*n/2
那如何处理这个剩余的部分呢?
其实可以对n进行乘除
d = left / n
r = left % n
把d赋值给每个元素,然后r这个尾巴相当于给最后的r个元素额外+1
小声哔哔,我也没写出来,看了挺多题解的,这个思路是最简单的了,但肯定不是唯一的构造方法。
兄弟们可以试着去证明一下,为什么这样一定能得到满足要求的数组。
我个人思考最关键的提示就是数组元素不能重复
,而我们是1~n大小构造起始数组的,如果前面数据增加就一定会和后面的数据重叠,除非你将后面重叠的数据全部增加,但这样数字大小最后一定会超过n,既然这样我为什么不每一个都加d呢,余下的r个数再分别加1,不就构造出满足要求的数组了嘛。
以上可以看作是充分性的“证明”,必要性估计就没有了~