time limit per test2 seconds
memory limit per test256 megabytes
Lesha plays the recently published new version of the legendary game hacknet. In this version character skill mechanism was introduced. Now, each player character has exactly n skills. Each skill is represented by a non-negative integer ai — the current skill level. All skills have the same maximum level A.
Along with the skills, global ranking of all players was added. Players are ranked according to the so-called Force. The Force of a player is the sum of the following values:
The number of skills that a character has perfected (i.e., such that ai = A), multiplied by coefficient cf.
The minimum skill level among all skills (min ai), multiplied by coefficient cm.
Now Lesha has m hacknetian currency units, which he is willing to spend. Each currency unit can increase the current level of any skill by 1 (if it’s not equal to A yet). Help him spend his money in order to achieve the maximum possible value of the Force.
Input
The first line of the input contains five space-separated integers n, A, cf, cm and m (1 ≤ n ≤ 100 000, 1 ≤ A ≤ 109, 0 ≤ cf, cm ≤ 1000, 0 ≤ m ≤ 1015).
The second line contains exactly n integers ai (0 ≤ ai ≤ A), separated by spaces, — the current levels of skills.
Output
On the first line print the maximum value of the Force that the character can achieve using no more than m currency units.
On the second line print n integers a’i (ai ≤ a’i ≤ A), skill levels which one must achieve in order to reach the specified value of the Force, while using no more than m currency units. Numbers should be separated by spaces.
Examples
input
3 5 10 1 5
1 3 1
output
12
2 5 2
input
3 5 10 1 339
1 3 1
output
35
5 5 5
Note
In the first test the optimal strategy is to increase the second skill to its maximum, and increase the two others by 1.
In the second test one should increase all skills to maximum.
这道题的意思是说,给你N个级别,满级是A,你总共还可以升M级,然后再给两个参数给你,cf和cm,然后有个式子:
满级的个数×cf+最低级的级数×cm
问,怎样分配M,使得这个式子的结果最大。
一开始我很天真的以为,尽量把大的升到满级,等到不够用了,再用剩下的来将最小的升级。然后成功地WA了。后来看了别人的博客才知道要枚举,因为有两个参数要相乘,所以并不是那么简单的贪心。而是要枚举升到满级的个数,然后再来求最小级别的级数。
然后在枚举满级的个数的时候,我们需要求的是最小级别的级数是多少。因为我们不知道怎样才能让最小的尽量大。
在这里我是一头雾水,然后,还是看了别人的博客,才一目了然。
先是将数字从大到小排序,然后从后往前求和。前面的,就是要用来枚举满级的个数的,后面的,就是用来将最小的尽量大。
我们假设有cnt个满级的,那么要将cnt个级别弄成满级的就需要
A*cnt-sum[1]+sum[cnt+1](我的for循环是从1开始的)个级别,所以一开始就要用M减去这些级别数。然后,剩下mm个级别可以让我们分配,这个时候我们很容易想到,我们把剩下的,未满级的级别数的总和求出来,算出平均数,然后把最小的,往平均数上面靠,就行了,然而并不是,因为这样算平均值,就说明要移动本来有的数字,然而那是不能移动的。
所以我们要找到一个位置h,从这个位置到最后的总和加上mm,然后算平均值,如果这个平均值大于或等于h这个位置上本来的数字,那么就将这个位置之后的所有数字都加到这个平均值上。
因为如果这个平均值大于或等于这个位置上本来的数字的话,就说明不需要移动这个数字我也能达到平均值。从左往右找,找到的第一个这样的位置就可以知道最小值的个数以及级别数了。当然,要找到这个位置,就要二分,我二分经常写挫就是了。
最后还有一点要注意的是初始化,一般我们初始化都是要初始化为0,但是我的这个代码不能简单地初始化为0,因为当M为0时,我是连循环都没有进去的,所以这个初始化,要根据一开始输入进去的数字来进行初始化,就是这一点坑了我好久,我曹。
还有里面算有多少个最小值的时候也要根据条件来初始化。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define maxn 100010
const int mod=1e9+7;
using namespace std;
struct node
{
ll val;
int wei;
}num[maxn];
ll sum[maxn];
ll n,a,cf,cm,m;
bool cmpv(node a,node b)
{
return a.val>b.val;
}
bool cmpw(node a,node b)
{
return a.weiint sear(int l,int r,ll m)
{
if(l==r) return l;
if(l>r) return r;
int mid=(l+r)/2;
ll f=sum[mid]+m;
int id=n-mid+1;
ll ff=min(f/id,a);
if(ff>num[mid].val) sear(l,mid,m);
else if(ff1,r,m);
else return mid;
}
int main()
{
while(scanf("%I64d %I64d %I64d %I64d %I64d",&n,&a,&cf,&cm,&m)!=EOF)
{
memset(num,0,sizeof(num));
memset(sum,0,sizeof(sum));
ll ans_cnt=0;
for(int i=1;i<=n;i++)
{
scanf("%I64d",&num[i].val);
if(num[i].val==a) ans_cnt++;
num[i].wei=i;
}
sort(num+1,num+n+1,cmpv);
for(int i=n;i>=1;i--)
{
if(i==n) sum[i]=num[i].val;
else sum[i]=num[i].val+sum[i+1];
}
ll cnt=0,mm=0,small=0,ans=0,big=0;
ll ans_small=num[n].val;
for(int i=0;i<=n;i++)
{
cnt=i;
if(cnt==0) mm=m;
else mm=m-(a*cnt-sum[1]+sum[cnt+1]);
if(mm<=0) break;
if(cnt+1>n) small=a;
else
{
int h=sear(cnt+1,n,mm);
small=min(a,(sum[h]+mm)/(n-h+1));
}
if(small==a) cnt=n;
big=small*cm+cnt*cf;
if(big>=ans)
{
ans=big;
ans_small=small;
ans_cnt=cnt;
}
}
for(int i=1;i<=n;i++)
{
if(i<=ans_cnt) num[i].val=a;
if(num[i].val1,num+n+1,cmpw);
ans=ans_cnt*cf+ans_small*cm;
printf("%I64d\n",ans);
printf("%d",num[1].val);
for(int i=2;i<=n;i++) printf(" %d",num[i].val);
printf("\n");
}
return 0;
}