题意:
给定 n 个整数,有 k 次机会可以使任意某个数增加或减少 x
问使得最后n个数乘积最小的序列是什么
思路:
首先要想到序列中可能存在负数
负数为负数时:整个序列乘积为负,要是序列乘积更小,我们可以找一个负数-x,也可以找一个正数+x
这时候就要考虑找哪个数:
假设有m个正数,ans = a1*a2*....*am 如果要选择一个数-x,让这个式子变小,我们暴力每一个数的话,可以知道:如果ai 减去x的话,那整个序列相当于减去 x*(ans / ai ) , x ,ans 都是定值,所以要选择ai 尽量小的数;
而本题也可以把这个序列的每个数的绝对值看成上述这个正数式子,无论负数的个数为奇数还是偶数,我们只需要考虑+x 或者-x,但是最优情况一定是选择绝对值最小的数操作
具体可以分情况 自己分析一下
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;
const int maxn = 2e5 + 7;
int n, k, x;
set<P> st;
ll a[maxn];
int main() {
scanf("%d%d%d", &n, &k, &x);
int t = 0; // 记录负数个数
for(int i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
if(a[i] < 0) t ^= 1;
st.insert(P(abs(a[i]),i));
}
for(int i = 0; i < k; ++i) {
int pos = st.begin()->second;
st.erase(st.begin());
if(a[pos] < 0) t ^= 1;
if(t) a[pos] += x;
else a[pos] -= x;
if(a[pos] < 0) t ^= 1;
st.insert(P(abs(a[pos]),pos));
}
for(int i = 1; i <= n; ++i) {
printf("%lld ", a[i]);
}
return 0;
}