时间: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;
}