Codeforces Round 963 (Div. 2) Problem B

原题链接:https://codeforces.com/contest/1993/problem/B

题目大意:

将一个数组中所有数字变成相同的奇偶性,能进行的操作只有任意选择2个数(a,b),使得小一点那个数字变成a+b,问最小操作数。

题目出发点:

因为要将所有数字变成相同奇偶性,以及这个操作,将2个数字中小一点数字变成2个数的和。众所周知,奇数+偶数=奇数,所以通过这个操作我们只能够得到将偶数变成奇数,而不能将奇数变成偶数。所以要做的事情就很明显了,就是找出这个数组中所有的偶数,然后相应一一匹配一个奇数去和偶数配对,把偶数进行 “变成2个数字的和” 的操作。

但是题目中写到要是最小操作数,所以为了使得操作数最小,要尽可能用最大的奇数去和小一点的偶数相匹配。所以我们可以在第一次循环中去找最大的奇数并记录下来,然后把所有的偶数去额外存一个数组,然后对这个数组排序,就可以从前往后匹配了。

vector <long long> a(n),b;
for(int i=0;i<n;i++)
		if(a[i]%2 == 1)
			jimax = max(jimax,a[i]);
		else
			b.push_back(a[i]);
sort(b.begin(),b.end());

但是这样做有点问题,那就是奇数的最大值是会变化的:

例如:5和4相匹配,4会变成9,然后9就会成为这个数组奇数中的老大,那么我们就应该将奇数最大值随着每次匹配变化,变成当前的最大值。

jimax = max(jimax,jimax+b[i]);

那么还有一种情况,就是如果当这个数组中最大的奇数比最小的偶数还要小的时候怎么办呢。那么我们的奇数就会先变成两个数的和,然后再去和偶数再匹配,所以就要次数+1,所以要额外定义一个变量来存储额外加的次数。

long long num=0;
if(jimax >= b[i])
			jimax = max(jimax,jimax+b[i]);
		else{
			num++;
			jimax = max(jimax,jimax+b[i]);
			jimax = max(jimax,jimax+b[i]);
		}

奇数最大值在额外加一次时也要额外进行一次重新赋值操作。

然后把这个额外加的次数+偶数个数就是答案了,对吗?

答案是错的,因为少考虑了一个点,那就是这个多加的次数最多为1

如果我要额外给奇数最大值进行变化赋值的话,我为什么不先从最大的偶数开始呢,这样就只需要额外加一次就可以了,所以这个次数最多为1,所以当检测到奇数最大值小于偶数时,可以直接把num变为1,然后停止循环了。

至于判断全奇数和全偶数的情况也很简单,只需要把奇数最大值的变量初始设置一个-1,如果有奇数那可能会比-1大,从而使得变量大于-1,如果寻找奇数后这个变量还是为-1的话就是全偶数了,如果存储偶数的数组为空的话,也是能说明这是全奇数了,直接输出0即可。

那么直接上代码:

#include<bits/stdc++.h>
using namespace std;
int t,n;
void solve(){
	long long jimax = -1,num = 0;
	cin>>n;
	vector <long long> a(n),b;
	for(int i=0;i<n;i++) cin>>a[i];
	for(int i=0;i<n;i++)
		if(a[i]%2 == 1)
			jimax = max(jimax,a[i]);
		else
			b.push_back(a[i]);
	if(jimax == -1 || b.empty()){
		cout<<0<<endl;
		return;
	}
	sort(b.begin(),b.end());
	for(int i=0;i<b.size();i++){
		if(jimax >= b[i])
			jimax = max(jimax,jimax+b[i]);
		else{
			num = 1;
			break;
		}
	}
	cout<<b.size()+num<<endl;
	return;
}
int main()
{
	cin>>t;
	while(t--)
		solve();
	return 0;
}

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值