题目传送门:http://codeforces.com/contest/613/problem/B
Two pointers的解法,就是喜欢优美的解法和装逼的姿势!!
首先存储的方式逼格就很高,比起之前的那种分着记录每一项高的多!
然后就是双指针法,外层指针指的是后几个满血的,内指针指的是前几个剩余钱能够满足的能力值最小的,因为随着满血的skill增加,内指针必定是要不断减小的,所以完美地O(n)解决此问题!!!
相比之下还是Two pointers的解法更优一点!
附上优美的英文注释
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MAX=1e5+9;
pair<ll,ll> a[MAX];//store initial skill and id
ll sum[MAX],res[MAX],n,cf,cm,m,A;
pair<ll,pair<ll,ll>> ans;// store sth we need
int main()
{
ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>A>>cf>>cm>>m;
for(int i=1;i<=n;i++) cin>>a[i].first,a[i].second=i;
sort(a+1,a+n+1);
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i].first;
ll p=n;
for(ll i=0;i<=n;i++)
{
ll d=m-i*A+sum[n]-sum[n - i];
if(d<0) break;
p=min(p,n-i);
while(p>1 && d<p*a[p].first-sum[p]) p--;
d-=p*a[p].first-sum[p];
ll k=min(A,i==n?A:(a[p].first+d/p));
//store ans,pos,minleval
ans=max(ans,{i*cf+k*cm,{i,k}});
}
cout<<ans.first<<'\n';
for(int i=0;i<ans.second.first;i++) a[n-i].first=A;
for(int i=1;i<=n;i++) a[i].first=max(a[i].first,ans.second.second),res[a[i].second]=a[i].first;
for(int i=1;i<=n;i++) cout<<res[i]<<" ";
}