题解:CF721D Maxim and Array
题意:
个数,最多进行 次操作,每次可以 或 ,求当 最小时的每个元素。
分析:
显然的,当这些数乘起来是一个正数时,我们如果把一个最靠近 的正数变成负数,或把一个最靠近 的负数变成正数,就可以用很小的代价取到较小值。
所以,如果我们发现它们初始乘起来是正数,那就找到一个绝对值最小的数,尽量把它变号,就可以用最小代价取到负数。
然后呢?
既然已经变成负数了,那肯定是绝对值的乘积越大越好(数字越小)。
如果某个数的绝对值较小,那么无论加 还是减 ,它对乘积的影响较小。 但是如果这个数的绝对值变大,对乘积影响会变大。因此,应该优先选择对绝对值最小的数进行操作,使其绝对值增大,从而最大化绝对值的乘积。
所以可以开一个小根堆,每次找绝对值最小的数,扩大它的绝对值就好啦。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
priority_queue<pair<ll, ll>, vector<pair<ll, ll> >, greater<pair<ll, ll> > > q;
ll n,k,x,a[1000000],re[1000000];
int main(){
ll rep=0;//判断正负,0为正,1为负
cin>>n>>k>>x;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]<0){
rep^=1;
re[i]=-1;//负数
}
else{
re[i]=1;//正数
}
q.push({abs(a[i]),i});
}
while(1){
if(q.empty()||!(k)){
break;
}
pair<ll,ll> xx=q.top();
//cout<<"*"<<xx.first<<" "<<xx.second<<endl;
q.pop();
if(a[xx.second]<0){
if(rep==0){
a[xx.second]+=x;
if(a[xx.second]>=0){
rep=1;
}
}
else{
a[xx.second]-=x;
}
}
else{
if(rep==0){
a[xx.second]-=x;
if(a[xx.second]<0){
rep=1;
}
}
else{
a[xx.second]+=x;
}
}
k--;
q.push({a[xx.second],xx.second});
}
for(int i=1;i<=n;i++){
cout<<a[i]<<" ";
}
}
//CF已AC
FOR WHAT???!!!