Codeforces Round #717 (Div. 2) C. Baby Ehab Partitions Again

看了官方题解之后,自己写一遍加深下印象。
2.cf Baby Ehab Partitions Again
传送门 :https://codeforces.com/contest/1516/problem/C
大意:给你一个长度为n 的序列 a,要求删除最少的元素个数,使得任意分成两组,这两组各自的和都不相等(可以不删除),输出删除的最少的元素个数,和要删除的下标。n不超过100

思维好题,解锁背包新用法
思路:先来想想什么情况下可以不删除? 很容易想到,如果原序列和为奇数的话,任意分两组必定都是不相等的两组。但和为偶数的时候的呢?因为和 s 是偶数,我们只需看其中一组能不能凑够是s/2就行了,不妨令m=s/2。接下来我们可以用01背包来判定。为什么呢?先让我们来想想01背包是用来干嘛的? 在不超过背包容量,每种商品最多取一次的前提下可以取到商品的最大价值!!!将本题代入01背包:即背包容量为m,求不超过m的选择方案的最大值,因为每个商品 体积==价值,总体积不超过背包容量m,所以选择的方案中的最大价值<=m,所以就可以用01背包来判断能不能凑成,即该最大价值是否和m相等。如果不等,即最大的都不等了,那凑不出了,所以就不用删。反之就是能凑出来,接下来进行下一步。

因为和是偶数。如果序列有奇数的话,删除这个奇数的话,和就变成奇数了,就不能分成相等的两组了。

但如果没有奇数呢?那简单,你们都是偶数,那我把你们都除以2不过分吧,因为你们到时候是看分组后的和嘛,除以2之后对你们又没什么影响。还没有奇数怎么办,那我再出一下再除一下不过分吧…还没有?我… 得,您被别除了,给您个奇数行了吧…

完毕。

#include <bits/stdc++.h>
#define pb push_back
#define scf scanf
#define prf printf
#define cs cout<<"\n"
#define cts cout<<"YES"<<"\n"
#define ctn cout<<"NO"<<"\n"
#define rep(i,bbb,eee) for(int i=bbb;i<=eee;i++)
#define per(i,bbb,eee) for(int i=bbb;i>=eee;i--)
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define _sy ios::sync_with_stdio(false);cin.tie(0)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
const int N=100010;
int a[110];
int n;
int f[N];
bool check()
{
	int s=0;
	rep(i,1,n)s+=a[i];
	if(s%2)return true;
	int m=s/2;
	for(int i=0;i<n;i++)
    {
        for(int j=m;j>=a[i];j -- )
            f[j] = max(f[j], f[j- a[i]] + a[i]);
    }
	return f[m]!=m;

}
void find()
{
	while(1)
	{
		rep(i,1,n)
		{
			if(a[i]%2)
			{
				cout<<1<<"\n"<<i<<"\n";
				return ;
			}
			a[i]/=2;
		}
	}
}
int main()
{
	_sy;
	cin>>n;
	rep(i,1,n)cin>>a[i];
	if(check())cout<<0<<"\n";
	else find();
	return 0;
} 

总结((1)可以用01背包模型来判断序列能否凑出和为某个数的问题(2)全是偶数时除以2的思想真的巧妙)

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值