CF1325D Ehab the Xorcist(位运算,思维)

CF1325D Ehab the Xorcist(位运算,思维)

题目

构造一个最短数组 \(a\) ,使得 \(\sum a_i = s\)。且 \(\oplus a_i = x\)。如果无法构造,输出-1

思路

如果思路正确,或者了解过一个结论,就是一眼题。可惜我太弱了中间想了些很假的思路。

首先说一下我的思路。

对于 \(x\) 如果某一位是 \(1\) 说明这位上至少有一个 \(1\)。那么不妨先让 \(s\) 减去 \(x\)

之后如果 \(s<0\) 说明无法构造。

那问题就变成构造 \(a\) 使得异或和为 \(0\) ,和为 \(s\)

这有一个非常好的性质,构造数组中每一位 \(1\) 都需要是偶数,那此时对于 \(s\) 的第 \(k\) 位为 \(1\) 。最好肯定直接补个 \(1\) 上去,但是因为要保证要有偶数个 \(1\) ,所以我们退而求其次可以在 \(k - 1\) 位上放置两个 \(1\)

按这样的方案构造,又会发现如果 \(s\) 最低位有 \(1\) 。就寄了,所以此时也是无法构造的。

最后我们找到了每一位 \(1\) 的个数,把它们贪心的放一起就可以了。如下

while(accumulate(cnt.begin(),cnt.end(),0ll)) {
		int cur = 0;
		rep(i,0,63) if(cnt[i]) cur |= (1ll << i), cnt[i] --;
		ans.push_back(cur);
	}

显然 \(1\) 的个数不会太多,上面的复杂度是可以接受的。


上面的思路建立在 异或运算每一位1的奇偶性和拆位统计1的个数 的想法上。

如果我们知道 \((a + b) = (a \oplus b) + (a\&b) * 2\) 这个公式,这个题做法就很显然了

由上有, \((a + b) - (a \oplus b) = 2 * (a \&b)\) 。当 \(s - x\) 为偶数可以构造出 $ {x,\frac{(s - x)}{2},\frac{(s - x)}{2} }$ 。的方案。

但此时还不最优。当 \(x \& \frac{s - x}{2} = 0\) 可以将两者合并,构造更优的方案。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#include<queue>
#include<map>
#include<string>
#include<random>
#include<iomanip>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
#define endl '\n'
#define int long long
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
using namespace std;
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;

void solve()
{    
	int x,s; cin >> x >> s;
	s -= x;
	if(s < 0 || s & 1) {
		cout << "-1\n";
		return;
	}
	vector<int> cnt(100);
	rep(i,0,63) {
		int bit = x >> i & 1;
		cnt[i] += bit;
	}
	rep(i,0,63) {
		int bit = s >> i & 1;
		if(bit) {
			cnt[i - 1] += 2;
		}
	}
	vector<int> ans;
	while(accumulate(cnt.begin(),cnt.end(),0ll)) {
		int cur = 0;
		rep(i,0,63) if(cnt[i]) cur |= (1ll << i), cnt[i] --;
		ans.push_back(cur);
	}
	cout << ans.size() << endl;
	for(auto it : ans) cout << it << " "; cout << endl;
}
signed main()
{
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

	//int T;cin>>T;
	//while(T--)
		solve();

	return 0;
}
posted @ 2022-06-21 22:46  Mxrurush  阅读(35)  评论(0)    收藏  举报