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 1in1 and assign ai=ai and ai+1=ai+1.

Input

The input consists of multiple test cases. The first line contains an integer t (1t1000) — the number of test cases. The descriptions of the test cases follow.

The first line of each test case contains an integer n (2n2105) — the length of the array.

The following line contains n space-separated integers a1,a2,,an (109ai109).

It is guaranteed that the sum of n over all test cases does not exceed 2105.

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个数有改变正负性的所有方案的最大值。根据前一个数ai1是否有改变正负性来划分集合,状态转移方程为

{f(i,0)=max{f(i1,0),f(i1,1)}+aif(i,1)=max{f(i1,0)2ai1,f(i1,1)+2ai1}ai

  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

posted @   onlyblues  阅读(74)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示