目录
题目:
题目描述:
给你长度为n的数组,再给你一个x,每次操作可以将数组中的一个数 ai 更新为 ai & x 问最少经过多少次操作可以让数组中两个位置出现一样的数
思路:
仔细观察题目数据范围,(1 ≤ ai ≤ 100 000) 很明显,可以用数组来存下标位置数值的个数。
然后我们再来分析以下题目中的操作。假如我们对数组中的一个数进行一次操作 ai & x == bi,那么就有(bi & x == bi)这个性质。
说明对于原数组中的一个数,只有第一次操作的时候才有可能产生新的数。
那么我们可以再开一个 b 数组,用来记录原数组( a 数组 )的所有数分别经过一次操作后的值,同样的,用数组来存下标位置数值的个数。
那么有几种可能让数组中两个位置出现一样的数 ?进行以下分类讨论:
①原数组( a 数组 )一开始就有重复的,操作次数是 0
②如果 b 数组中找到了对应 a 数组中的数,且这两个数位置不同,则说明 1 次操作可以达成题意
③如果 b 数组中某个下标的数值大于等于2,说明我们可以通过 2 次操作,将原数组( a 数组 )中的两个数进行转化成相同的数
④如果上面三种情况都没出现,那说明无论多少次操作也不会出现重复的数,输出 -1
所以按照 ①→②→③→④ 的顺序操作,找到符合要求的情况就输出并跳出即可
思路有了,具体操作请看AC代码:
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
const int inf = 2e9 + 5;
int a[N];
int b[N];
int main()
{
std::ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n, x;
cin >> n >> x;
for (int i = 1; i <= n; i++)
{
int temp;
cin >> temp;
if (a[temp])
{
cout << 0 << '\n';
return 0;
}
a[temp]++;
}
for (int i = 0; i < N; i++)
{
if (a[i] == 0)continue;
int temp = i;
if (a[temp & x] && (temp & x) != i)
{
cout << 1 << '\n';
return 0;
}
b[temp & x]++;
}
for (int i = 0; i < N; i++)
{
if (b[i] >= 2)
{
cout << 2 << '\n';
return 0;
}
}
cout << -1 << '\n';
return 0;
}