CF1516C

C. Baby Ehab Partitions Again

这个题比 B 简单吧

比赛时花了 \(23\) 分钟切了。

其实我们可以得出结论,最多去掉一个数。

至于为什么需要在分析的过程中解释。

首先,如果 \(n\) 个数的和为奇数一定输出 \(0\)。这个很好理解。

其次,我们再来考虑是否存在一种划分方式满足一些数之和为 \(\frac{sum}{2}\)。这个其实很简单,裸的背包。没有这种划分方式输出 \(0\),否则要删掉一个数。

我们可能不发通过删除一个数导致无法划分,但是我们可以让 \(sum\) 的奇偶性发生改变。

如果此时全都是偶数,就 \(\div 2\),直到出现了奇数为止。

//Don't act like a loser.
//This code is written by huayucaiji
//You can only use the code for studying or finding mistakes
//Or,you'll be punished by Sakyamuni!!!
#include<bits/stdc++.h>
#define int long long
using namespace std;

int read() {
	char ch=getchar();
	int f=1,x=0;
	while(ch<'0'||ch>'9') {
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9') {
		x=x*10+ch-'0';
		ch=getchar();
	}
	return f*x;
}

const int MAXN=1e5;

int n,sum;
int a[MAXN];
bool f[2][MAXN];

void div() {
	while(1) {
		for(int i=1;i<=n;i++) {
			if(a[i]&1) {
				cout<<1<<endl<<i<<endl;
				return ;
			}
			a[i]>>=1;
		}
	}
}

signed main() {
	cin>>n;
	for(int i=1;i<=n;i++) {
		a[i]=read();
		sum+=a[i];
	}
	if(sum&1) {
		cout<<0<<endl;
		return 0;
	}
	
	int m=sum/2;
	fill(f[0],f[0]+m+1,0);
	f[0][0]=1;
	for(int i=1;i<=n;i++) {
		for(int j=0;j<=m;j++) {
			f[i%2][j]=f[(i-1)%2][j];
			if(j>=a[i]) {
				f[i%2][j]=f[i%2][j]|f[(i-1)%2][j-a[i]];
			}
		}
	}
	if(!f[n%2][m]) {
		cout<<0<<endl;
		return 0;
	}
	
	div();
	return 0;
}

posted @ 2021-04-23 19:32  huayucaiji  阅读(104)  评论(0编辑  收藏  举报