题目及翻译
题面
LZY又来恶心人啦,在n个整数中,最多取k个整数,求最大和且和为奇数。
输入
本题有多组测试样例,输入一对正整数n (n<100000) 和 k (k<=n)。
紧接着跟着n个整数ai(-2147483648<=ai<=2147483647)题目保证至少有一个奇数。
输出
求符合题意的最大奇数和。
输入样例
6 3
9 7 5 3 1 -1
输出样例
21
题目思路
lzy出的好题,乍一看很简单,随便写写,怎么都过不去,看题解的情况下,愣是用dfs对拍了一下午,实际上是我的小细节没有考虑清楚
题目要求用最多m个数组成最大奇数和,那么可以确定以下几点(题目保证一定有奇数输入):
1 答案内一定包含最大的那个奇数
2 答案内可以包含奇数个奇数
3 答案内可以包含任意(不超过m-奇数个数)个偶数
确定了这几点,可以把偶数奇数分开算
奇数处理方式:
首先把奇数从大到小排序,拿出最大的那个奇数
其次把其他奇数从小到大,两两分组求和,这样他们在加入答案时不会影响奇数的数量
这样就得到了以1个、3个、5个…这样的奇数个奇数的组合序列,来满足第二点
偶数处理方式:
只取正偶数,并从大到小排序,对于每个奇数组合,尽可能填上多的偶数,直到用了m个数或正偶数用完
这样只要把所有奇数组合能得到的最大值算一遍即可得出答案
注意事项
m个数可以不用完
可能只有负数奇数或只有一个奇数
需要使用longlong
AC代码
C/C++(代码几乎没有变更)
用时280MS 内存4528K 长度864B
#include<iostream>
#include<algorithm>//sort
using namespace std;
typedef long long ll; //方便写long long
ll n,m,a,res,len1,len2,len3;
ll v1[100010],v2[100010],v3[100010];//分别存奇数,偶数,奇数组合
int main(){
ios::sync_with_stdio(false);
while(cin>>n>>m){//输入
len1 = len2 = len3 = 0;//初始化三个数组的长度
for(ll i=0;i<n;++i){//输入n个数
cin>>a;
if(a&1)v1[len1++] = a;//如果是奇数就存入奇数数组
else if(a > 0)v2[len2++] = a;//如果是偶数且大于0就存入偶数数组
}
sort(v1,v1 + len1,greater<ll>());//从小到大排序
sort(v2,v2 + len2,greater<ll>());//同上
v3[len3++] = v1[0];//奇数组合第一个数只需要一个数
for(ll i=1;i+1<len1&&i+1<m;i+=2){//记录3开始的奇数组合,并且使用数量不能超过m个
v3[len3] = v3[len3-1] + v1[i] + v1[i+1];
++len3;
}
for(ll i=1;i<len2;++i){//把偶数数组变为前缀和方便计算
v2[i] += v2[i-1];
}
res = -2147483648;//初始化为最小值
for(ll i=0;i<len3;++i){//遍历所有奇数组合,维护一个最大的答案
ll flag = m - (i * 2 + 1);//flag为剩余可用的数字个数
if(!flag)res = max(res,v3[i]);//如果不可用,就直接更新答案
else if(flag <= len2)res = max(res,v3[i] + v2[flag-1]);//如果偶数够用,就尽可能多的使用
else res = max(res,v3[i] + v2[len2-1]);//如果偶数不够用,就把所有偶数都用上
}
cout<<res<<endl;//输出答案
}
return 0;
}
本文作者 优快云@扶她小藜
个人主页链接 https://blog.youkuaiyun.com/weixin_44579869