题解:P10412 「QFOI R2」钟声远带斜阳
首先分析题意。
因为数列无限延长而总和恒非负。
所以这个数列总和非负。
形象地理解就是说,如果数列总和为负数,无限求和就一定会是负数,不满足题意。
而如果总和非负,从头开始无限求和也不会出现负数。
下面用数学公式表达转化后的题意。
求使原式满足上面这个式子所需最小代价。
然后考虑题目给出的三种操作。
对于操作一,给哪个数加一对结果没有影响,可以最后考虑。
对于操作二,删除绝对值较大的负数有时比操作一更优。
对于操作三,交换位置事实上对结果没有影响。
因此想到用贪心解决,下面简单讲下思路。
如果原总和非负,不用操作就满足题意,答案输出零即可。
如果原总和是负数,考虑贪心解决。
首先将原数组从小到大排序,因为越小的负数,使用操作二就更优。
从前往后遍历序列。
如果用操作二更优,就用操作二。
如果用操作一更优,就用操作一把总和加到零,因为数组已经排序,后面的数用操作二不会更优。
输出总代价即可。
特别地,需要记录删除数的个数,以满足不能将数列删空的要求。
下面提供参考代码。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN=1e5+10;
int a[MAXN],n,p,q,r,cnt,cost,sum;
signed main(){
cin>>n>>p>>q>>r;
for(int i=1;i<=n;i++) cin>>a[i],cnt+=a[i];
if(cnt>=0){
cout<<0<<'\n';
return 0;
}
sort(a+1,a+1+n);
cnt=-cnt;
for(int i=1;i<=n;i++) if(a[i]<0){
if(cnt<=0){
break;
}
if(q<=p*min(cnt,-a[i])&&sum<n-1){
cost+=q;
cnt+=a[i];
a[i]=0;
sum++;
}else{
cost+=p*min(cnt,-a[i]);
cnt-=min(cnt,-a[i]);
a[i]+=min(cnt,-a[i]);
}
}
cout<<cost<<'\n';
return 0;
}