CF1516C 题解

提速偷懒小技巧

使用 bitset 自带的位运算配上 01 背包,真是又快速又省代码长度!

思路

首先设 s=ais=\sum a_i,若 smod2=1s\bmod2=1,显然最开始就是好的,不用删;否则可以先用 01 背包判断是否存在子序列之和为 s2\frac s2 的,如果不存在,说明最开始也是好的,也不删。

否则,我们只要设 gg 表示每个 aia_i 都除得尽的最大的 2g2^g,这时只要删去任意一个 aimod2g+10a_i\bmod2^{g+1}\ne0 的数即可使 smod2g+10,smod2g=0s\bmod2^{g+1}\ne0,s\bmod2^g=0

本人喜欢使用位运算,如果代码看不懂我会在注释中写等价代码。

代码

# include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair <int, int> pii;
int n, sum, a[105], g = 2048;
bitset <2000005> dp;
int main () {
	ios::sync_with_stdio (0);
	cin.tie (0);
	cout.tie (0);
	cin >> n;
	for (int i = 0; i < n; ++ i)
		cin >> a[i], sum += a[i];
	if (sum & 1) { //奇数
		cout << 0;
		return 0;
	}
	dp[0] = 1;
	for (int i = 0; i < n; ++ i)
		dp |= dp << a[i]; //bitset 自带的位运算,用法详见 OI-wiki
	if (! dp[sum >> 1]) { //没有 sum 的一半
		cout << 0;
		return 0;
	}
	for (int i = 0; i < n; ++ i)
		sum = min (sum, a[i] & -a[i]); //lowbit 算法
	for (int i = 0; i < n; ++ i)
		if (a[i] & sum) { //如果 a[i] / sum % 2 = 1,则 a[i] 的二进制位上一定有 sum 这一位,否则没有
			cout << "1\n" << i + 1;
			return 0;
		}
	cout << -1;
	return 0;
}
posted @ 2024-05-17 19:49  Vitamin_B  阅读(16)  评论(0)    收藏  举报  来源