Codeforces 721D Maxim and Array[贪心]

题意:给定n个数,每个数的绝对值小于1e9,需要进行k次操作,每次操作可以使一个数+x或-x,问k次操作之后每个数相乘结果最小的n个数。

思路:首先当n个数中有奇数个负数,那么当前乘积已经是负数了,我们只要对绝对值最小的数加或减得到的结果就是最小的,用一个优先队列处理。

当n个数中只有偶数个负数时,我们可以选择把绝对值最小的那个数变正,或负,如果k不够,那么直接在这个数上处理k次,得到的结果也是最小的。

代码如下:

#include<cstdio>
#include<queue>
#include<cmath>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct lx {
	long long val;
	int id;
}p[200005];
struct cmp {
	bool operator()(const lx &a, const lx &b) const//优先队列按照绝对值大小排序。
	{
		return abs(a.val)>abs(b.val);
	}
};
long long ans[200005];
priority_queue<lx, vector<lx>, cmp>qe;
int cmp1(lx a, lx b) {
	return a.val<b.val;
}
int cmp2(lx a, lx b) {
	return abs(a.val)<abs(b.val);
}
int main() {
	int n, k, num = 0;
	long long x;
	scanf("%d%d", &n, &k);
	scanf("%I64d", &x);
	for (int i = 0; i<n; ++i) {
		scanf("%I64d", &p[i].val);
		p[i].id = i;
		if (p[i].val<0)num++;//判定负数的个数
	}
	if (num & 1) {//负数是奇数个的情况
		for (int i = 0; i<n; ++i)qe.push(p[i]);//将n个数放入优先队列
		for (int i = 0; i<n; ++i) {
			ans[p[i].id] = p[i].val;
		}
		while (k != 0) {//每次对绝对值最小的那个数处理
			lx temp = qe.top(); qe.pop();
			if (temp.val<0) {//如果是小于0的就减x,大于等于0的就加x
				temp.val -= x;
				ans[temp.id] -= x;
			}
			else {
				temp.val += x;
				ans[temp.id] += x;
			}
			k--;
			qe.push(temp);
		}
		for (int i = 0; i<n; ++i)cout << ans[i] << " ";
	}
	else {
		sort(p, p + n, cmp1);//按照大小排序
		if (num != 0) {//因为需要比较p[num-1].val和p[num].val防止越界就分类了,可能可以改的更短
			if (num != n) {//
				if (abs(p[num - 1].val)<abs(p[num].val)) {
					if (abs(p[num - 1].val) / x + (abs(p[num - 1].val) % x == 0 ? 0 : 1) <= k) {//变号需要的操作比k小
						k -= (abs(p[num - 1].val) / x + (abs(p[num - 1].val) % x == 0 ? 0 : 1));
						p[num - 1].val += x*(abs(p[num - 1].val) / x + (abs(p[num - 1].val) % x == 0 ? 0 : 1));
						if (p[num - 1].val == 0 && k>0) {//如果变成了0且k还不为0,再操作一次变号
							p[num - 1].val += x;
							k--;
						}
					}
					else {
						p[num - 1].val += k*x;
						k = 0;
					}
				}
				else {
					if (p[num].val / x + (p[num].val%x == 0 ? 0 : 1) <= k) {
						k -= p[num].val / x + (p[num].val%x == 0 ? 0 : 1);
						p[num].val -= x*(p[num].val / x + (p[num].val%x == 0 ? 0 : 1));
						if (p[num].val == 0 && k>0) {
							p[num].val -= x;
							k--;
						}
					}
					else {
						p[num].val -= k*x;
						k = 0;
					}
				}
			}
			else {
				if (abs(p[num - 1].val) / x + (abs(p[num - 1].val) % x == 0 ? 0 : 1) <= k) {
					k -= (abs(p[num - 1].val) / x + (abs(p[num - 1].val) % x == 0 ? 0 : 1));
					p[num - 1].val += x*(abs(p[num - 1].val) / x + (abs(p[num - 1].val) % x == 0 ? 0 : 1));
					//cout << p[num - 1].val << endl;
					if (p[num - 1].val == 0 && k>0) {
						p[num - 1].val += x;
						k--;
					}
				}
				else {
					p[num - 1].val += k*x;
					k = 0;
				}
			}
		}
		else {
			if (p[num].val / x + (p[num].val%x == 0 ? 0 : 1) <= k) {
				k -= p[num].val / x + (p[num].val%x == 0 ? 0 : 1);
				p[num].val -= x*(p[num].val / x + (p[num].val%x == 0 ? 0 : 1));
				if (p[num].val == 0 && k>0) {
					p[num].val -= x;
					k--;
				}
			}
			else {
				p[num].val -= k*x;
				k = 0;
			}
		}
		//处理完之后也是奇数个负数或k为0的情况,接下来就跟上面一样
		for (int i = 0; i<n; ++i)qe.push(p[i]);
		for (int i = 0; i<n; ++i) {
			ans[p[i].id] = p[i].val;
		}
		while (k != 0) {
			lx temp = qe.top(); qe.pop();
			if (temp.val<0) {
				temp.val -= x;
				ans[temp.id] -= x;
			}
			else {
				temp.val += x;
				ans[temp.id] += x;
			}
			k--;
			qe.push(temp);
		}
		for (int i = 0; i<n; ++i)cout << ans[i] << " ";
	}
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值