【思维题】CodeForce 1013B And

这段时间要沉迷刷题一段时间了,就让CSDN陪我一起吧!

一、题目大意

给定两个数字n和x,其中n是数组的长度,然后再给出n个数,是数组元素。规定每次操作可以将数组的其中一个元素a[i]用a[i]&x替换,求至少需要多少次操作,才能使数组中存在至少两个相同的元素?

二、题目思路以及AC代码

我真是没想到codeforce上也有题目这么坑的题。简直被坑惨,不同的理解完全不同的思路。

在这里我们需要好好的考虑以下这句话:
在这里插入图片描述
要注意这里的some i 指的是某个i的意思,而不是一些。

我一开始就是按照一些的思路去做的,当然思路也不难,我也很快写出来了,可就是WA,想了半天也没有想出为什么,最后看到别人的题解才发现,题目真坑啊!!!(一会下面我也贴一下我错误理解题目的代码,大家如果也做了的话可以对一下)

然后就是正确的题目了,正确题目的思路也不是很难,主要是需要想清楚一个问题,一个数与另一个数做按位与,做一次、两次、三次…的结果都是一样的,这个结论也很好理解。知道了这个结论之后,下面我们就很简单了,对于本题来说,就只需要考虑两个数组的问题,一个是原数组(记为a),一个是将原数组元素都和x进行与运算之后的数组(记为b)。

如果a数组中有相等的元素,那么不需要做操作就可满足条件,则输出0;
如果a数组中没有相等元素,b数组中也没有相等元素,因为再进行与运算也都和b数组一样,所以就说明无论操作多少次也都没有相等元素,那么输出-1;
如果a数组中没有相等元素,b数组中有相等元素,那么说明是存在的,下面就需要考虑是1次操作还是2次操作的问题:
 对于1次操作,是a数组的某个元素与x做与操作之后正好等于a数组中的另一个元素。
 对于2次操作,是a数组中的某个元素与x做与运算之后,等于a数组中的另一个元素和x做与运算。

基于以上的思路就可以写出代码了:

#include <iostream>
#define MAXN 100010
using namespace std;

int n, x;
int a[MAXN];
int b[MAXN];
int visa[MAXN];
int visb[MAXN];

int main()
{
	
	cin >> n >> x;

	bool flag = false;
	bool flag1 = false;
	for (int i = 0; i < n; i++) {
		cin >> a[i];
		b[i] = a[i] & x;
	}

	for (int i = 0; i < n; i++) {
		if (visa[a[i]]) {
			flag = true;
			break;
		}
		visa[a[i]] = true;
	}
	if (flag) {
		cout << 0 << endl;
	}
	else {
		for (int i = 0; i < n; i++) {
			if (visb[b[i]]) {
				flag1 = true;
				break;
			}
			visb[b[i]] = true;
		}
		if (!flag1) {
			cout << -1 << endl;
		}
		else {
			for (int i = 0; i < n; i++) {
				if (visa[b[i]] && b[i] != a[i]) {
					flag = true;
					break;
				}
			}
			if (flag)
				cout << 1 << endl;
			else
				cout << 2 << endl;
		}
	}

    return 0;
}

我原来那个错误理解的代码也不能白写,就也贴在下面吧,下面给出的是把some按照一些来理解的代码:

#include <iostream>
#define MAXN 100010
using namespace std;

int n, x;
int a[MAXN];
bool vis[MAXN];

void init() {
	for (int i = 0; i < MAXN; i++) {
		vis[i] = false;
	}
}

int main() {

	init();

	cin >> n >> x;

	for (int i = 0; i < n; i++) {
		cin >> a[i];
	}

	bool flag = true;
	for (int i = 0; i < n; i++) {
		if (vis[a[i]]) {
			flag = false;
			break;
		}
		vis[a[i]] = true;
	}

	if (!flag) {
		cout << 0 << endl;
	}
	else {
		int step = 0;
		bool isFind = false;
		do {
			bool flag = false;
			step++;
			for (int i = 0; i < n; i++) {
				int tmp = a[i] & x;
				if (tmp == a[i]) continue;

				flag = true;
				if (vis[tmp]) {
					isFind = true;
					break;
				}
				vis[tmp] = true;
				a[i] = tmp;
			}
			if (!flag) {
				break;
			}
		} while (!isFind);

		if (isFind) cout << step << endl;
		else cout << -1 << endl;
	}


	return 0;
}

如果有问题,欢迎大家指正!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值