E. Negatives and Positives
E. Negatives and Positives
Given an array consisting of elements, find the maximum possible sum the array can have after performing the following operation any number of times:
- Choose adjacent elements and flip both of their signs. In other words choose an index such that and assign and .
Input
The input consists of multiple test cases. The first line contains an integer () — the number of test cases. The descriptions of the test cases follow.
The first line of each test case contains an integer () — the length of the array.
The following line contains space-separated integers ().
It is guaranteed that the sum of over all test cases does not exceed .
Output
For each test case, output the maximum possible sum the array can have after performing the described operation any number of times.
Example
input
5 3 -1 -1 -1 5 1 5 -5 0 2 3 1 2 3 6 -1 10 9 8 7 6 2 -1 -1
output
1 13 6 39 2
Note
For the first test case, by performing the operation on the first two elements, we can change the array from to , and it can be proven this array obtains the maximum possible sum which is .
For the second test case, by performing the operation on and , we change the array from to , which has the maximum sum since all elements are non-negative. So, the answer is .
For the third test case, the array already contains only positive numbers, so performing operations is unnecessary. The answer is just the sum of the whole array, which is .
解题思路
比赛的时候一直想着贪心怎么写,然后一直在那wa,最后还是老老实实写dp过了,回来看题解的时候发现还真是贪心解法,就是一直没发现题目的某个性质。
注意到不管我们执行了多少次的操作,数组中负数个数的奇偶性总是保持不变(在一次取反后,要么是增加或者减少两个负数,要么是增加一个负数和减少一个负数)。
因此如果一开始数组中有偶数个负数,那么我们总是可以通过若干次的操作使得负数的个数变成,因此答案就是所有数的绝对值之和。
如果一开始数组中有奇数个负数,那么最终至少要有一个负数,所有我们可以让数组中绝对值最小的那个数为负数(如果有的话则选择),那么答案就是其他数的绝对值之和再减去这个最小数的绝对值。
AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 6 void solve() { 7 int n; 8 scanf("%d", &n); 9 int cnt = 0, minv = 2e9; 10 LL s = 0; 11 while (n--) { 12 int x; 13 scanf("%d", &x); 14 if (x < 0) cnt++, x *= -1; // 统计负数 15 s += x; 16 minv = min(minv, x); // 找到绝对值最小的那个数 17 } 18 if (cnt & 1) s -= 2 * minv; // 有奇数个负数 19 printf("%lld\n", s); 20 } 21 22 int main() { 23 int t; 24 scanf("%d", &t); 25 while (t--) { 26 solve(); 27 } 28 29 return 0; 30 }
再给出dp的做法。
定义状态表示前个数中,且第个数没有改变正负性的所有方案的最大值。表示前个数中,且第个数有改变正负性的所有方案的最大值。根据前一个数是否有改变正负性来划分集合,状态转移方程为
AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 6 const int N = 2e5 + 10; 7 8 int a[N]; 9 LL f[N][2]; 10 11 void solve() { 12 int n; 13 scanf("%d", &n); 14 for (int i = 1; i <= n; i++) { 15 scanf("%d", a + i); 16 } 17 f[2][0] = a[1] + a[2], f[2][1] = -a[1] + -a[2]; 18 for (int i = 3; i <= n; i++) { 19 f[i][0] = max(f[i - 1][0], f[i - 1][1]) + a[i]; 20 f[i][1] = max(f[i - 1][0] - 2 * a[i - 1], f[i - 1][1] + 2 * a[i - 1]) - a[i]; 21 } 22 printf("%lld\n", max(f[n][0], f[n][1])); 23 } 24 25 int main() { 26 int t; 27 scanf("%d", &t); 28 while (t--) { 29 solve(); 30 } 31 32 return 0; 33 }
参考资料
Codeforces Round #849 (Div. 4) Editorial:https://codeforces.com/blog/entry/112282
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17091709.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效