洛谷 CF1257F Make Them Similar 灰 题解

前言

本题解采用折半搜索算法完成,对于不打算用这种方法的同学,这篇题解可能会浪费你人生中宝贵的十几分钟。

思路

此题似乎找不出什么好的性质,那么考虑暴力。

发现 \(x,a\) 都在 \(2^{30}\) 内,直接枚举必然无法承受,怎么办?折半!

我们把 \(x,a_i\) 劈成两半,一半为前 \(15\) 位,一半为后 \(15\) 位,分别暴力计算。

\(c_i\) 表示 \(a_i \oplus x\) 得到的数的前 \(15\) 位的 \(1\) 的个数(前 \(15\) 位,指:从高往低数前 \(15\) 位);

\(d_i\) 表示 \(a_i \oplus x\) 得到的数的后 \(15\) 位的 \(1\) 的个数(后 \(15\) 位,指:从低往高数前 \(15\) 位)。

那么 \(c_i + d_i\) 就表示 \(a_i \oplus x\) 得到的数在二进制表示下 \(1\) 的个数,题目要求所有的 \(c_i + d_i\) 必须相等,那么我们可以列出必须满足的式子:\(c_i + d_i = c_{i-1} + d_{i-1},\ 2 \le i \le n\)

你会发现这个式子没有简单的判定方法,那考虑把式子换一种形式,既然要保证所有的 \(c_i + d_i\) 相等,那么只要满足 \(c_i + d_i = c_1 + d_1\) 就可以了。

貌似有一些思路,但是还没有复杂度较低的判定方法,那就再把式子换一种形式:\(c_i - c_1 = d_1 - d_i\),这样就可做了。

实现

我们求 \(c\) 数组的时候把每一个 \(x\) 所对应的所有 \(c_i - c_1\) 存下来。求 \(d\) 数组的时候,把所有 \(d_1 - d_i\) 存下来。

如果某一个 \(x\),与其对应的 \(c_i - c_1\)\(d_1 - d_1\) 每一项都相等,那么就满足条件了,输出即可。

插曲

如何快速地求一个数在二进制下的 \(1\) 的个数?先上代码~

int get_cnt(int val)
{
	int res = 0;
	while (val) val &= val - 1, res ++ ;
	return res;
}

我们举个例子来看一看

总的来说 \(x-1\) 相当于是把 \(x\) 在二进制表示下最靠后的 \(1\) 以及这个 \(1\) 后面的所有 \(0\) 按位取反,得到的数再与上 \(x\) 相当于把最靠后的 \(1\) 消去了。

Code

#include <iostream>
#include <cstring>
#include <map>
#include <vector>

using namespace std;

const int N = 110;
const int Mo = (1 << 15) - 1;

int n;
int a[N];
map<vector<int>, int> mp;

int get_cnt(int val)
{
	int res = 0;
	while (val) val &= val - 1, res ++ ;
	return res;
}

int main()
{
	cin >> n;
	for (int i = 1; i <= n; i ++ ) cin >> a[i];
	for (int x = 0; x < (1 << 15); x ++ )
	{
		int c1 = get_cnt((a[1] >> 15) ^ x);
		vector<int> vec;
		for (int i = 2; i <= n; i ++ ) vec.push_back(get_cnt((a[i] >> 15) ^ x) - c1);
		mp[vec] = x;
	}
	for (int x = 0; x < (1 << 15); x ++ )
	{
		int d1 = get_cnt((a[1] & Mo) ^ x);
		vector<int> nw;
		for (int i = 2; i <= n; i ++ ) nw.push_back(d1 - get_cnt((a[i] & Mo) ^ x));
		if (mp.count(nw))
		{
			cout << (mp[nw] << 15) + x << endl;
			return 0;
		}
	}
	cout << -1 << endl;
	return 0;
}

完结撒花

这是我折半搜索第一次学明白的题了,也是我第一道灰题!收~

posted @ 2022-09-27 16:48  LittleMoMol  阅读(108)  评论(0编辑  收藏  举报
*/