D - Decrease (Contestant ver.)
Time limit : 2sec / Memory limit : 256MB
Score : 600 points
Problem Statement
We have a sequence of length N consisting of non-negative integers. Consider performing the following operation on this sequence until the largest element in this sequence becomes N−1 or smaller.
- Determine the largest element in the sequence (if there is more than one, choose one). Decrease the value of this element by N, and increase each of the other elements by 1.
It can be proved that the largest element in the sequence becomes N−1 or smaller after a finite number of operations.
You are given an integer K. Find an integer sequence ai such that the number of times we will perform the above operation is exactly K. It can be shown that there is always such a sequence under the constraints on input and output in this problem.
Constraints
- 0≤K≤50×1016
Input
Input is given from Standard Input in the following format:
K
Output
Print a solution in the following format:
N a1 a2 ... aN
Here, 2≤N≤50 and 0≤ai≤1016+1000 must hold.
这道题真的非常有意思,有着极简的代码但是很有趣的思考过程.
题目大意就是说给你一个k,这个k是long long范围内的,你需要构造一个数列,使得满足以下要求.
( 设你所构造的这个序列长度为N)
1.对于每一次操作,我们会挑出这个这个数列数值最大的数,使它减去一个N,其他所有数全部加上一个1.
2.当最大值<N的时候,则不能再进行操作.
3.你所构造的这个数列进行k次操作之后恰好不能再操作,即所有数都小于N.
注意有Special Judge.(输出一组可行解即可).
建议大家在看题解的时候自己先思考十来分钟,说不定你会有一个很精妙的办法解决它,如果没想出来,再看题解也会为这道题一个精巧的思路所称赞.
这个数列长度不定,k又那么大,减去一个数其它数又增长起来,最大值不定...感觉完全无思路.
有多组可行解...我们试着想到了2-Sat或网络流或拓扑排序有类似输出可行方案但是没有依赖关系,没有真假之类的,又找不到建图的思路...没思路....
当我们找不到思路的时候,我们试想着将无序转换为有序,不能掌握变成完全掌握.因为每次我们选择的最大数是不定的,所以对于某一个数减下去,我们需要知道下一个冉冉升起的最大值是谁,这是我们需要掌握的.
那么如果,我们构造得了,当前最大值减下去,剩下的最大值就是原来的次大值的数列,我们就能让一切尽在掌握之中.我们想到了一个排好序的序列,从大到小,第一个数减下去,第二个数成最大值,第二个数减下去,第三个数成最大值...我们固定一个序列长度为50(上限为50)的数列,为50,49,48,47........................3,2,1.
我么发现第一个数减下去,数列变为0,50,49,48,47,.............4,3,2,一轮下来(每个数都减一遍,操作50次),就成了49,48,47,46.................,2,1,0,相当于每个数都减去了一个1.也就是说对于k=50,这是一个可行解.由于刚刚一轮减下来,所有数全减1的性质,k=100的时候 : 51,50,.........,4,3,2是一组可行解. 那么对于所有k为50的倍数,我们都能找到一个合法方案.
显然,k不一定是50的倍数.这也就意味着我们把这个数列从1号位置每个数减一遍想成一轮,那么k也就是在某一轮‘卡’住了,这个‘游戏’玩不下去了.
那么我们把这个想成一个游戏,1-50号就是50个玩家.每个人拥有多个积分,一轮下来每个人损失一个积分(就如同那个性质),当积分小于50的时候这个玩家就不能玩了.题目中的k次我们想成一共可以玩k次,每一轮50个玩家都玩一次,即消耗50次.那么对于每个人积分都一样的时候,那么每一轮都是完整的,也就是说整数次轮之后大家都不能玩了,玩的次数是一样的.那么‘卡’在某一轮的情况,我们设卡在i位,i+1之后的刚好不能玩了(映射到原来就是,当前最大值i号位减下去,i+1号位作为最大值<50),那么也就是说1~i号玩家刚好比i+1~50号玩家多一个积分.这也就意味着我们所谓电玩场老板,我们只要合理分配积分,刚好玩k次就能结束整场游戏,打烊关门.
怎么合理分配积分?对于数列上每一个数我们是从大到小的排列,也就是说初始值是这么多号数唯一的不同.那么我们就可以把这些数所抽象成的玩家分配不同的初始积分即可.由于一轮消耗一个积分,那么也就是说在j轮过后,第i位变成了0,i+1变成了49刚好小于50,也就对应了‘第i+1号玩家刚好不能玩了,k此结束’,由于在第i为变成0之前,i与i+1,分别为50,48 此轮之前进行了整数次,消耗了相同的积分,也就是初始化每个玩家的积分,i~i+1成了一个断层,刚好差了2.其它数互相之间只差1,因为如果i与i+1差了只有1的话,那么原来只差了1,i减下去其他所有数全部加1,i能玩下一次i+1还能继续玩下去,差了2就刚好在某一轮,i玩下去了,i+1就不能玩了.2变成了东非大裂谷.
最后,我们只需要算出k/n最多能玩的轮数,以及k/n的余数那里就是东非大裂谷(玩到余数那里就结束,k次刚好消耗完).想见代码,输入k=50,51,52三组数据有助于理解我们走么设置‘东非大裂谷’的位置的.
注意交程序只能用lld...
#include<stdio.h>
int main(){
long long k;
scanf("%I64d",&k);
puts("50");
for(long long i=0;i<=49;i++)
printf("%I64d ",49-i+((49-i+k)/50));
}