题意:给定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] << " ";
}
}