题面
分析
首先明确一点,所有数的和(为sum)一定时 ∑ i = 1 n a i k ⩽ s u m k \sum_{i = 1}^{n} \frac{a_i}{k} \leqslant \frac{sum}{k} ∑i=1nkai⩽ksum。因为如果你分出来了一个小于 k - 1 的数,剩下的数的和除以 k 要么减小 1,要么不变。而如果分出来的数大于 k - 1,那么一定可以表示成若干个 k 和一个小于 k - 1 的数的和的形式,很显然他减小的部分一定大于等于分出来这个数增加的部分(那若干个 k 就已经可以补上了,而那个小于 k - 1 可能使他更小)。
无解
首先分析无解情况,如果 s k < b \frac{s}{k} < b ks<b 则一定无解,还有另一种情况下面会说。
构造
我们可以不断地分出 k - 1 这样除了过后的和一定会不断减小,而且这样的做法一定是减的最多的,理由如上。因此我们只需要给最大的那个数留下 m i n ( s , k ∗ ( b + 1 ) − 1 ) min(s, k * (b + 1) - 1) min(s,k∗(b+1)−1) ,剩下的一直分 k - 1 直到分不够为止即可,min 是为了考虑刚好是 b 的情况。当然,如果我们分满了 n - 1 个还有剩余,则是另一种无解情况,输出 -1 即可。
代码实现
//省略快读和头文件
int T;
ll n, k, b, s;
ll num[MAXN], cnt = 0;
int main()
{
T = inpt();
while(T--) {
n = inpt(), k = inpt(), b = inpt(), s = inpt();
if(s / k < b) {//无解情况 1
puts("-1");
continue;
}
cnt = 0;
num[++cnt] = min(s, k * (b + 1) - 1);//留下的大数
s -= num[cnt];
while(s) {
if(s > k - 1) {//不断的分
num[++cnt] = k - 1;
s -= k - 1;
}else {//记得还可能有余
num[++cnt] = s;
s = 0;
}
if(cnt > n)//无解情况 2,这个也可以提前处理
break;
}
if(cnt <= n) {
for(int i = 1; i <= cnt; i++)
printf("%lld ", num[i]);
for(int i = cnt + 1; i <= n; i++)//记得剩下的要补 0
printf("0 ");
puts("");
}else {
puts("-1");
}
}
return 0;
}