Codeforces Round #339 (Div. 2) D. Skills

本文介绍了一种游戏角色技能提升的优化算法,通过合理分配资源来最大化玩家在游戏中所扮演角色的能力值,具体包括技能等级和角色综合能力的计算方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

D. Skills
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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 nAcfcm and m (1 ≤ n ≤ 100 0001 ≤ A ≤ 1090 ≤ 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.

     这道题要求解最小值*cm+A的个数*cf的最大值。因为要求解数组的最小值,首先想到排序。按照从小到大排序。并且记录下标。这样要求这个表达式的最大值,越靠近末尾的数字越接近A。但是让数组末尾出现连续的A这样能否保证最优性呢?要让表达式的值最大,我们首先要尽可能把m值用完。当a[i]=A,a[i+1]<A并且在m尽可能用完的情况下,我们让a[i]达到A,花费A-a[i];这样还不如让a[i+1]达到A,此时花费为A-a[i+1]。因为a[i]<=a[i+1],则A-a[i+1]<=A-a[i],a[i+1]要达到A会比a[i]更容易些。这样就满足了贪心的原理。就可以从n向1开始遍历,即让数组末尾达到A的个数不断增加。当然需要注意的第一点就是遍历从n+1到2,从n+1开始相当于没有元素达到A,然后就只需要提高最小值。但是有个地方就是如果此时最小值达到了A,虽然我们假定的是在n+1时,没有元素达到A。这样就矛盾了。所以对最小值还要特殊判断是否为A。这种情况实际上相当于把所有元素都加满到A。也就是m够用,可以把所有数字加到A。然后遍历的下界为2的理由是因为如果遍历到1的话,相当于已经满足了所有的数字都被加满到A。这种情况就重复了,之前处理过,所以就不用考虑。在m足够将k个末尾数字加到A的情况下,在1~n-k的范围内,要找到一个高度h,让1~pos的范围内的数字都相等,且为最小值。也就是把1~pos加满到h。 

      这个地方开始傻逼了,假设当前位置为i,就天真地觉得1~i-1的sum值加上m剩下的值再除以i-1就是h。后来才发现这特么的必须保证移动这个范围内的数字才可以保证每个数字都为h。所以这个h不能这么求。。。只能在数组最小值min~A的范围内二分枚举。然后找到最合适的位置。                                                       

      还有一个坑就是一直用int变量,结果很容易在乘法的时候爆掉int。                                                                                                                                       

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define CLR(x) memset(x,0,sizeof(x))
#define REP(i,l,r) for(int i=l;i<=r;i++)
#define RREP(i,l,r) for(int i=l;i>=r;i--)
#define _s(x) scanf("%d",&x)
#define _sc(x) scanf("%c",&x)
#define _ss(x) scanf(" %s",x)
#define _sl(x) scanf("%I64d",&x)
#define _sd(x) scanf("%lf",&x)
#define _pt(x) printf("%d",x)
#define _ps(x) printf("%s",x)
#define _pc(x) printf("%c",c)
#define _pl(x) printf("%I64d",x)
#define _pn printf("\n");
#define _p printf(" ");
#define ll long long

using namespace std;

int n,cf,cm;
int a[100010],b[100010],id[100010];
ll A,m,sum[100010];

inline bool cmp(const int& x,const int& y) {
    if(a[x]==a[y]) return x<y;
    return a[x]<a[y];
}

ll check(ll h,int i){
   if(h>b[i]) return h*i-sum[i];
   int pos=lower_bound(b+1,b+i+1,h)-b;
   if(b[pos]==h){
     return h*pos-sum[pos];
   }else{
     if(pos==1){
       return 0;
     }else{
       return h*(pos-1)-sum[pos-1];
     }
   }
}

int main() {
    while(~scanf("%d%I64d%d%d%I64d",&n,&A,&cf,&cm,&m)) {
        sum[0]=0;
        REP(i,1,n) {
            _s(a[i]);
            b[i]=a[i];
            id[i]=i;
        }
        sort(id+1,id+n+1,cmp);
        sort(b+1,b+n+1);
        REP(i,1,n) {
            sum[i]=sum[i-1]+a[id[i]];
        }
        ll ans=-1;
        int ht=0,cr=0;
        if(m-(n*A-sum[n])>=0){
            ans=n*cf+A*cm;
            printf("%I64d\n",ans);
            for(int i=1;i<=n;i++)
                printf("%d ",A);
            printf("\n");
            continue;
        }
        RREP(i,n+1,2) {
            ll cnt=(n-i+1)*cf;
            ll res=m-((n-i+1)*A-(sum[n]-sum[i-1]));
            if(b[i-1]==A) continue;
            if(res<0) break;
            int l=b[1],r=A;
            while(l<r){
                int mid=(l+r)>>1;
                ll num=check(mid,i-1);
                if(num<=res) l=mid+1;
                else r=mid-1;
            }
            while(l>=b[1]&&check(l,i-1)>res) --l;
            cnt+=(ll)l*cm;
            if(cnt>ans){
                ans=cnt;
                ht=l,cr=i;
            }
        }
        _pl(ans);_pn;
        REP(i,1,n){
           if(a[id[i]]<=ht) a[id[i]]=ht;
           if(i>=cr) a[id[i]]=A;
        }
        REP(i,1,n){
           _pt(a[i]);_p;
        }
        _pn;
    }
}

内容概要:该研究通过在黑龙江省某示范村进行24小时实地测试,比较了燃煤炉具与自动/手动进料生物质炉具的污染物排放特征。结果显示,生物质炉具相比燃煤炉具显著降低了PM2.5、CO和SO2的排放(自动进料分别降低41.2%、54.3%、40.0%;手动进料降低35.3%、22.1%、20.0%),但NOx排放未降低甚至有所增加。研究还发现,经济性和便利性是影响生物质炉具推广的重要因素。该研究不仅提供了实际排放数据支持,还通过Python代码详细复现了排放特征比较、减排效果计算和结果可视化,进一步探讨了燃料性质、动态排放特征、碳平衡计算以及政策建议。 适合人群:从事环境科学研究的学者、政府环保部门工作人员、能源政策制定者、关注农村能源转型的社会人士。 使用场景及目标:①评估生物质炉具在农村地区的推广潜力;②为政策制定者提供科学依据,优化补贴政策;③帮助研究人员深入了解生物质炉具的排放特征和技术改进方向;④为企业研发更高效的生物质炉具提供参考。 其他说明:该研究通过大量数据分析和模拟,揭示了生物质炉具在实际应用中的优点和挑战,特别是NOx排放增加的问题。研究还提出了多项具体的技术改进方向和政策建议,如优化进料方式、提高热效率、建设本地颗粒厂等,为生物质炉具的广泛推广提供了可行路径。此外,研究还开发了一个智能政策建议生成系统,可以根据不同地区的特征定制化生成政策建议,为农村能源转型提供了有力支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值