题目背景
HJZ 有很多玩具。他最喜欢玩的玩具是一个可以变化的数组。
题目描述
HJZ 的数组初始时有 n 个元素。他可以把一个位置上的数加上或减去一个固定的
数 x。
一天 LJZ 和 HZY 来 HJZ 家玩。LJZ 突发奇想,提出了一个问题:如何在给定的
操作步数内最小化数组所有元素的乘积呢?
HJZ 百思不得其解,但是他想博得 HZY 的好感,就把这个问题交给你啦 ~
由于最小乘积可能很小,HJZ 只需要你给出
. 最 . 小 . 乘 . 积 . 对 10^9 + 7
. 取 . 模的结果。
. 请 . 注 . 意 . 一 . 个 . 数 . 对 p . 取 . 模 . 的 . 结 . 果 . 一 . 定 . 是 . 非 . 负 . 数, . 即 . 你 . 输 . 出 . 的 . 结 . 果 ans
. 要 . 满 . 足 0 ≤ ans < 10^ 9 + 7 。
输入输出格式
输入格式:
从文件 array.in 中读入数据。
第一行三个整数 n,k, x 分别表示数组元素个数、最多操作次数和每次操作的数。
第二行 n 个整数 a 1 ,a 2 ,...,a n 表示数组初始时的元素。
输出格式:
输出到文件 array.out 中。
一行一个在 [0,10 9 + 7) 范围内的整数,表示最小乘积的绝对值对 10 9 + 7 取模的
结果。
输入输出样例
输入样例#1:
3 2 7 5 4 2
输出样例#1:
999999732 【样例 1 解释】 最多可以进行两次操作,每次把一个位置 +7 或 −7 。 最优策略是将数组第二个元素 +7 ,第三个元素 −7 ,得到新的数组 5 11 − 5 ,乘 积为 5 × 11 × (−5) = −275 ,模 10 9 + 7 的结果是 999999732 。
输入样例#2:
5 3 1 5 4 3 5 5
输出样例#2:
0 【样例 2 解释】 只能把一个位置 +3 或 −3 ,把第三个位置 −3 最优,乘积为 0 。 【子任务】 对于所有测试点,1 ≤ n,k ≤ 2 × 10^5 ,1 ≤ x ≤ 10^9 ,|a i | ≤ 10^9 。
分析:数据很大,不可能dp,稍微做过一点贪心题的人能够一眼看出这道题就是用贪心做,但是具体怎么贪心比较难想,如果我们能让乘积变成负数是最好的,如果当前的乘积是正数,那么我们要先用最少的步数让乘积变成负数,这个时候操作绝对值最小的数让它变成符号相反的数就能使乘积变成负数了.
要使每次操作的贡献最大,肯定是操作绝对值最小的数,如果绝对值最小的数是正数,就让他增加x,否则就让它减少x,乘积还是负数,而且每一次的贡献是最大的,所以答案一定是最优的,每次找绝对值最小的数用优先队列.
需要注意对于0的处理.
#include <cstdio> #include <functional> #include <cstring> #include <iostream> #include <algorithm> #include <queue> #include <cmath> using namespace std; const long long mod = 1000000007; long long n, k, x,ans = 1,cnt; priority_queue <long long> q1; //存负数 priority_queue <long long, vector<long long>, greater<long long> >q2; //存正数 void jian() { long long y = q2.top(); q2.pop(); while (k && y) { k--; y -= x; if (y <= 0) { q1.push(y); return; } } q2.push(y); } void jia() { long long y = q1.top(); q1.pop(); while (k && y <= 0) { k--; y += x; if (y > 0) { q2.push(y); return; } } q1.push(y); } int main() { scanf("%lld%lld%lld", &n, &k, &x); for (int i = 1; i <= n; i++) { long long t; scanf("%lld", &t); if (t <= 0) { q1.push(t); cnt++; } else q2.push(t); } //先让乘积变成负数 if (cnt % 2 == 0) { if (cnt == 0) jian(); else if (cnt == n) jia(); else if (abs(q1.top()) < abs(q2.top())) jia(); else jian(); } for (int i = 1; i <= k; i++) { long long t1, t2; if (!q1.empty()) t1 = q1.top(); else t1 = -100000000000000; if (!q2.empty()) t2 = q2.top(); else t2 = 100000000000000; if (abs(t1) > abs(t2)) { q2.pop(); t2 += x; q2.push(t2); } else { q1.pop(); t1 -= x; q1.push(t1); } } while (!q1.empty()) { ans = (ans * (q1.top() % mod)) % mod; q1.pop(); } while (!q2.empty()) { ans = (ans * (q2.top() % mod)) % mod; q2.pop(); } while (ans < 0) ans += mod; printf("%lld ", ans); return 0; }