ZJYYOJ 最大奇数和(思维好题)[C,C++]

针对LZY提出的复杂问题,本篇详细解析了如何在限制条件下找到最大奇数和的算法策略。通过将奇数和偶数分别处理,结合深度优先搜索(DFS)与动态规划思想,最终实现高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目及翻译

题面

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值