cf round613(div2) D - Dr. Evil Underscores (分治,递归)

题目链接
题目大意:给定n个数,找一个数x让x和这n个数里异或的最大值最小.输出这个最小的最大值.
位运算的题一般都是拆位运算.按位考虑怎么做
分析一下样例
1 2 3
拆位
0 1
1 0
1 1
我们要最大值最小.考虑如何去构造.要么从大到小构造要么从小到大构造(大小指的是位数)这题是要从大到小构造(可以看完做法再来想为什么).
因为要构造最大值最小.我们考虑最高位.如果说这一位上面的数有0也有1,无论我们用1异或它还是用0异或它.最后都是1.不过这里就形成了两条分支(分治的思想从此而来).看样例. 分成了 0(1) 和 1(0,1)这两条路.这两条路的解决方案和原先是一样的.只不过规模变小了.我们只需要取这两条路里面比较小的一条就可以了.而如果这一位上面全是0或者全是1,贪心的方法肯定是让它最后结果变成0.所以直接搜索下一位就好了.
不过这里有一个还要解决的问题是怎么实现0(1)和1(0,1)这样子的待选方案.
代码里使用了vector容器来做.考虑过空间会不会爆的问题.不过还好没爆…
附上代码

#define LL long long 
#define pb push_back
#include <bits/stdc++.h>
using namespace std;
LL gcd(LL a,LL b){return b == 0 ? a : gcd(b,a%b);}
const int N = 1e5+10;

int n;
int dfs(vector<int> v,int pos){
	if(pos < 0) return 0;
	vector<int> v1,v0;
	for(int i=0;i<v.size();++i){
		if( (v[i] >> pos) & 1 ) v1.pb(v[i]);
		else v0.pb(v[i]);
	}
	if(v1.empty() || v0.empty()){
		return dfs(v,pos-1);
	}
	else return (1 << pos) + min(dfs(v1,pos-1),dfs(v0,pos-1));
}
int main(){
	cin >> n;
	vector<int> v;
	int maxx = 0;
	for(int i=1;i<=n;++i){
		int x;
		cin >> x;
		maxx = max(maxx,x);
		v.pb(x);
	}
	int pos = 0;
	for(int i=29;i>=0;--i) if(maxx & (1 << i)){ pos=i;break;}
	cout << dfs(v,pos);
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45590210/article/details/105220158