题解:CF721D Maxim and Array

题意:
nn 个数,最多进行 kk 次操作,每次可以 +x+xx-x ,求当Πi1nai\Pi_{i-1}^na_i 最小时的每个元素。

分析:
显然的,当这些数乘起来是一个正数时,我们如果把一个最靠近 00 的正数变成负数,或把一个最靠近 00 的负数变成正数,就可以用很小的代价取到较小值。

所以,如果我们发现它们初始乘起来是正数,那就找到一个绝对值最小的数,尽量把它变号,就可以用最小代价取到负数。

然后呢?

既然已经变成负数了,那肯定是绝对值的乘积越大越好(数字越小)。

如果某个数的绝对值较小,那么无论加 xx 还是减 xx,它对乘积的影响较小。 但是如果这个数的绝对值变大,对乘积影响会变大。因此,应该优先选择对绝对值最小的数进行操作,使其绝对值增大,从而最大化绝对值的乘积。

所以可以开一个小根堆,每次找绝对值最小的数,扩大它的绝对值就好啦。

#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
posted @ 2024-11-24 21:08  MistyPost  阅读(5)  评论(0编辑  收藏  举报  来源