CodeForce500B-And-好题-分类讨论

题目传送门
题意:
给定一个数x和一个数组,求要经过几次与x的&操作才能是数组出现两个相同的元素。
思路:
先给出官方题解:
Clearly, if it is possible then there are no more than 2 operations needed.
So we basically need to distinguish 4 outcomes —  - 1, 0, 1 and 2.
The answer is zero if there are already equal elements in the array.
To check if the answer is -1 we can apply the operation to each element of the array. If all elements are still distinct, then it couldn’t be helped.
To check if the answer is one we can bruteforce the element a to apply the operation to, and if this operation changes this element, we can check if there is an a & x element in the array.
In all other cases answer is two.
我觉得就看官方题解吧,英文看起来要正式一点。
然后我写一下自己的思维过程,刚开始,我想把每个数分解成二进制,保存下来,后来发现个复杂度高了一点。
我们可以敏锐发现答案就是4种情况,-1,0,1,2。
我们可以先判断0,-1,1的情况,然后剩下的就是2的情况。
其实就是这样的,因为2的情况比较复杂,因为两两组合的复杂度有O(n^2)。这提示我们先考虑问题的简单面,然后剩下的就是复杂面了。
再说一下-1的解法,这个可能会被想当然认为是反面,但是它不是(复杂的)。我们直接将全部的都与x进行&操作,看最后有没有相同的,因为将全部的都&包含了1,2的情况。这种一不做,二不休的做法感觉牛,细想起来还是很有味道的。
这对于分类讨论题是一种启发。

AC code:
#include<iostream>
#include<cstdio>
#include<vector>
#include<bitset>
#include<stack>
#include<set>
#include<queue>
#include<map>
#include<cmath>
#include<string>
#include<cstring>
#include<ctime>
#include<fstream>
#include<cstdlib>
#include<algorithm>

using namespace std;

//#define pii pair<int, int>
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define per(i,a,b) for(int i=a;i<=b;i++)
#define rep(i,a,b) for(int i=a;i>=b;i--)
#define all(x) x.begin(),x.end()
#define PER(i,x) for(auto i=x.begin();i!=x.end();i++)
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
typedef long long LL;
typedef pair<int,int> pii;
const double eps=1.0e-5;
const int maxn=3e5 + 10;
int dx[4] = {0,0,-1,1};
int dy[4] = {1,-1,0,0};
int n = 0,x = 0; 
int a[maxn],b[maxn];
void solve(){
	per(i,1,n){//判断0的情况 
		if(a[i] == a[i-1]){
			printf("0\n");
			return ;
		}
	}
	per(i,1,n){//判断-1的情况 
		b[i] = a[i] & x;
	}
	b[0] = -1;
	sort(b+1,b+n+1);
	bool flag = false;
	per(i,1,n){
		if(b[i] == b[i-1]){
			flag = true;
			break;
		}
	}
	if(flag == false){
		printf("-1\n");
		return ;
	}
	
	per(i,1,n){//判断1的情况 
		if(a[i] == (a[i] & x)){
			continue;
		}
		if(
		//lower_bound(a+1,a+1+n,a[i] & x) != a+n+1 && //画蛇添足,导致WA 
		//lower_bound(a+1,a+1+n,a[i] & x) != (a + 1)  && 
		*lower_bound(a+1,a+1+n,a[i] & x) == (a[i] & x)){
			printf("1\n");
			return ;
		}
	}
	printf("2\n");//其它全是2的情况 
}
int main(){
	#ifndef ONLINE_JUDGE
		//freopen("a.txt","r",stdin);
	#endif
	while(~scanf("%d %d",&n,&x)){
		per(i,1,n){
			scanf("%d",&a[i]);
		} 
		sort(a+1,a+n+1);
		solve(); 
	}
	
	return 0; 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值