#717 div2 C题 思维+背包

该博客探讨了一种算法问题,即如何在最少删除数字的情况下,确保一个数字序列无论如何划分成两个子序列,它们的和都不相同。当序列总和为奇数时,直接返回0;若为偶数,则通过动态规划判断是否能构造和为总和一半的序列,如果可以,只需移除一个奇数;若序列中没有奇数,可以通过将所有数除以2直至出现奇数并移除。代码实现使用C++,包括动态规划和01背包策略。

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

C. Baby Ehab Partitions Again
题意:给一串数字,问你最少删几个数能保证无论怎么把操作完的这串数分成两个子序列,两段的数字和都不一样。
首先sum如果是奇数,可以直接判输出0。
如果是sum偶数,我们只需要判断这些数找到构成和为sum/2的序列,dp判断(01背包)能不能有数字能凑出来sum/2,如果可以踹走一个奇数就行。但如果原序列一个奇数都没有,我们发现对这个序列同时除以2是不影响答案的,因为如果存在两个序列和相等, 那么对等式两边同时除以 2 2 2 不会有影响,因此我们一直除直到有一个数变成奇数,踹走这个数就行。因此我们证明了如果要删那最多删一个,删的那个一定是质因数分解后2次幂最低的那个数,因此我们读入的时候把这个数搞出来就行了。
code:

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 9;
int n;
int a[N];
int f[N];
int Min = 0x3f3f3f3f, pos = 2;
int sum;
int main()
{
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i)
	{
		scanf("%d", &a[i]);
		sum += a[i];
		int tmp = a[i], k = 0;
		while(tmp % 2 == 0){
			++k; tmp/=2;
		}
		if(k < Min) Min = k, pos = i;
	}
	if(sum & 1) cout << 0 << endl;
	else 
	{
		memset(f,0,sizeof(f));
		f[0] = 1;
		for(int i = 1; i <= n; ++i)
		{
			for(int j = sum;  j >= 0; --j)
				if(f[j]) f[j + a[i]] = 1;
		}
		if(f[sum/2]) cout << 1 << "\n" << pos << endl;
		else cout << 0 << endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值