E. Negatives and Positives
E. Negatives and Positives
Given an array $a$ consisting of $n$ elements, find the maximum possible sum the array can have after performing the following operation any number of times:
- Choose $2$ adjacent elements and flip both of their signs. In other words choose an index $i$ such that $1 \leq i \leq n - 1$ and assign $a_i = -a_i$ and $a_{i+1} = -a_{i+1}$.
Input
The input consists of multiple test cases. The first line contains an integer $t$ ($1 \leq t \leq 1000$) — the number of test cases. The descriptions of the test cases follow.
The first line of each test case contains an integer $n$ ($2 \leq n \leq 2\cdot10^5$) — the length of the array.
The following line contains $n$ space-separated integers $a_1,a_2,\dots,a_n$ ($-10^9 \leq a_i \leq 10^9$).
It is guaranteed that the sum of $n$ over all test cases does not exceed $2\cdot10^5$.
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 $[-1, -1, -1]$ to $[1, 1, -1]$, and it can be proven this array obtains the maximum possible sum which is $1 + 1 + (-1) = 1$.
For the second test case, by performing the operation on $-5$ and $0$, we change the array from $[1, 5, -5, 0, 2]$ to $[1, 5, -(-5), -0, 2] = [1, 5, 5, 0, 2]$, which has the maximum sum since all elements are non-negative. So, the answer is $1 + 5 + 5 + 0 + 2 = 13$.
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 $1 + 2 + 3 = 6$.
解题思路
比赛的时候一直想着贪心怎么写,然后一直在那wa,最后还是老老实实写dp过了,回来看题解的时候发现还真是贪心解法,就是一直没发现题目的某个性质。
注意到不管我们执行了多少次的操作,数组中负数个数的奇偶性总是保持不变(在一次取反后,要么是增加或者减少两个负数,要么是增加一个负数和减少一个负数)。
因此如果一开始数组中有偶数个负数,那么我们总是可以通过若干次的操作使得负数的个数变成$0$,因此答案就是所有数的绝对值之和。
如果一开始数组中有奇数个负数,那么最终至少要有一个负数,所有我们可以让数组中绝对值最小的那个数为负数(如果有$0$的话则选择$0$),那么答案就是其他数的绝对值之和再减去这个最小数的绝对值。
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的做法。
定义状态$f(i,0)$表示前$i$个数中,且第$i$个数没有改变正负性的所有方案的最大值。$f(i,1)$表示前$i$个数中,且第$i$个数有改变正负性的所有方案的最大值。根据前一个数$a_{i-1}$是否有改变正负性来划分集合,状态转移方程为
\begin{cases}
f(i,0) = \max\{ f(i-1,0), f(i-1,1) \} + a_i \\
f(i,1) = \max \{ f(i-1,0) -2a_{i-1}, f(i-1,1) + 2a_{i-1} \} - a_i
\end{cases}
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