1月5号 B题 小信去旅游

文章描述了一个关于旅行规划的问题,小信需要在n个城市中选择最多k次旅行,每次旅行会增加快乐值,但城市快乐值会递减。解决方案是采用贪心算法,首先对城市快乐值排序,然后优先选择最高值的城市,直到快乐值为0或者旅行次数用完。给出的超时代码通过排序和比较来寻找最大值,而优化后的代码避免了重复排序,通过计算差值和等差数列求和来提高效率,以找到最大可能的快乐值。
摘要由CSDN通过智能技术生成

时间:1s 空间:256M

题目描述:

 小信制定了一个包含n个城市的旅游计划。每个城市初始能给小信带来的快乐值表示为数组a。

他可以按任意顺序去至多k次不同城市。当小信到达一个城市i,他的快乐值会增加ai,然后城市i能为他带来的快乐值ai就会减少1。

小信的初始快乐值为0,求小信能获得的最大快乐值。

输入格式:

第一行,包含两个正整数 n,k,表示城市数和小信至多旅游次数。

第二行包含n个整数a1,a2,...,an,表示每个城市初始能给小信带来的快乐值。

输出格式:

输出一行整数,表示小信能获得的最大快乐值。

样例1输入:

3 5
10 12 5

样例1输出:

52

样例2输入:

2 114514
1919 810

样例2输出:

2170695

约定与提示:

对于100%的数据,1≤n≤105;1≤k,ai≤2×1e9。

样例1解释:

小信去城市1旅游2次,去城市2旅游3次,获得的快乐值为 (10+9)+(12+11+10)=52。

题意:

有n个数,每次可以任选一个数,加到的总和中,选完后,这个数要减1,一共可以选k次,要求最后总和最大。

思路:

很明显是个贪心,就先将n个数排序,然后循环判断a[1]是否大于0,不做这个判断会导致结果负数,接下来在判断a[1]是否>=a[2] 如果大了就让sum+=a[1],小的话,就重新排序同时加上拍完序的a[1],但是每一遍都要重新排序很烦,超时了。

超时代码:

#include <bits/stdc++.h>
using namespace std;
long long n,k,sum=0;
long long a[100005];
bool cmp(int x,int y){
    return x>y;
}
int main(){
    scanf("%lld%lld",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=k;i++){
        if(a[1]>=0){    
            if(a[1]>=a[2]){
                sum+=a[1];
                a[1]--;
            }
            else{
                sort(a+1,a+n+1,cmp);
                sum+=a[1];
                a[1]--;
            }
        }
        else break;
    }
    printf("%lld",sum);
    return 0;
} 

思路:

我们不妨想想怎么优化,思路没问题,找最大的去,但不用重新排序,比如说第一次排序过后,我们去看最大的和第二大的差多少,这个过程所需的此数就是最大的减最小的差,然后用等差数列算出此过程的总和(第二大的+最大的)*次数=这些次数所能带来的最大快乐值,当然还是要判断是否==0,若==0就跳出循环输出sum,当然计算过程中要有一个数记录当前次数是否超过k,然后将思路整合一下就可以了。

代码:

#include <bits/stdc++.h>
using namespace std;
long long n,k,times=0,plies=1,p;//times表示次数,plies代表层数(因为每次推下去,最大的数减至第二大如果还有次数就要继续往下推,但是它的次数就不只最大的到第二大的所需次数,后面还要加第二大到第三大的.....以此类推) 
long long a[1000005],sum=0;
bool cmp(int x,int y){
    return x>y;
} 
int main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }   
    sort(a+1,a+n+1,cmp);
    for(int i=1;k!=0;i++){
        p=a[i];
        times=plies*(p-a[i+1]); //层数×a[i]至a[i+1]所需次数 
        if(p==0) break; 
        if(times>=k){
            if(k%plies==0){
                sum+=(p+(p-k/plies+1))*(k/plies)/2*plies;//(首项+末项)×项数/2×层数 
                k=0;
            }
            else{
                sum+=(p+(p-k/plies+1))*(k/plies)/2*plies+(k%plies)*(p-k/plies);//首项+末项)×项数/2×层数 +还能加的快乐值 
                k=0; 
            }
        }
        else{
            sum+=(p+a[i+1]+1)*(p-a[i+1])/2*plies;//首项加末项的和×项数/2乘上层数 
            k-=(p-a[i+1])*plies;
            p=a[i+1];
            i++;
            while(p==a[i]){
                i++;
                plies++; 
            }
            i-=2;

        }
    }
    cout<<sum;
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值