给定一个长度为 nn 的整数序列 a1,a2,…,ana1,a2,…,an。
请你找到一个该序列的子序列,要求:
- 该子序列的所有元素之和必须是奇数。
- 在满足条件 11 的前提下,该子序列的所有元素之和应尽可能大。
输出你找到的满足条件的子序列的所有元素之和。
保证至少存在一个满足条件的子序列。
注意,子序列不一定连续。
输入格式
第一行包含一个整数 nn。
第二行包含 nn 个整数 a1,a2,…,ana1,a2,…,an。
输出格式
输出一个整数,表示满足条件的子序列的所有元素之和。
数据范围
前 66 个测试点满足 1≤n≤51≤n≤5。
所有测试点满足 1≤n≤1051≤n≤105,−104≤ai≤104−104≤ai≤104。
输入样例1:
4
-2 2 -3 1
输出样例1:
3
输入样例2:
3
2 -5 -3
输出样例2:
-1
思路如下:
把正数加起来,不是奇数就max(sum-最小正奇数,sum + 最大负奇数),是奇数就输出即可。
当都是负数时,只需要取最小负奇数就行了。
代码如下:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
const int N = 1e5 + 10;
int a[N]; // 存所有的数
int zj[N]; // 存正奇数
int fj[N]; // 存负奇数
int zo[N]; // 存正偶数
int fo[N]; // 存负偶数
typedef long long ll;
ll sum = 0;
int n1, n2, n3, n4;
int main() {
scanf("%d", &n);
for(int i = 0; i < n; i ++) {
scanf("%d", &a[i]);
}
sort(a, a + n);
reverse(a, a + n); // 从大到小排个序
for(int i = 0; i < n; i ++) {
if(a[i] > 0) {
if((a[i] & 1) == 1) zj[n1 ++] = a[i]; // 存正奇数
else zo[n2 ++] = a[i]; // 存正偶数
}
else if (a[i] == 0) continue;
else {
if((a[i] & 1) == 1) fj[n3 ++] = a[i]; // 存负奇数
else fo[n4 ++] = a[i]; // 存负偶数
}
}
for(int i = 0; i < n; i ++) {
if(a[i] >= 0) {
sum += a[i]; // 将所有正数加起来
}
}
if (sum != 0) { // 当有正数时
if(sum & 1) { // 恰好是奇数,输出,结束
printf("%lld", sum);
return 0;
}
else { // 不是奇数,sum = max(sum + 最大负奇数,sum - 最小正奇数)
if(n1 == 0) sum = sum + fj[0]; // 没有正奇数
else if(n3 == 0) sum = sum - zj[n1 - 1]; // 没有负奇数
else sum = max(sum - zj[n1 - 1], sum + fj[0]); // 两者都有
printf("%lld", sum);
return 0;
}
}
else { // 没有正数时
if(fj != 0) { // 取最小负奇数即可
printf("%d", fj[0]);
return 0;
}
}
return 0;
}