题目大意:

有数列An,在数列中若任意两个数a,b。若a & b !=0 ,我们则在a,b之间连一条线。问已知An,形成的最小的圈的节点的个数。

解题思路:

由于n=1e5,所以我们不能很naive的建图,每个点都查询,否则复杂度到达n^2。这时候,我们发现,从二进制位来看,若三个或以上数字的同一位都是1,那么可以直接输出3。这个key,导致了我们建图的复杂度大大降低为 nlogn + 60*n ,其中60表明我们只用60位二进制即可,而新生成的图的边数也会小于60,这样我们找圈也成为了可能!

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int UNVISITED = 0;
const int VISITED = 1;
const int EXPLORED = 2;
const int MAXN = 1e5 + 10;
int bit[MAXN][65];
vector<vector<int>> gra(MAXN);
int ans;
int dfs_num[MAXN];
int dfs_parent[MAXN];
int cur[MAXN];
void dfs_find_circle(int u, int level) {
dfs_num[u] = VISITED;
cur[u] = level;
for (int i = 0; i<(int)gra[u].size(); i++) {
int nx = gra[u][i];
if (dfs_num[nx] == UNVISITED) {
dfs_parent[nx] = u;
dfs_find_circle(nx, level + 1);
}
else if (dfs_num[nx] == VISITED) {
if (dfs_parent[u] == nx)continue;
else {
ans = min(abs(cur[u] - cur[nx])+1, ans);
}

}
else if (dfs_num[nx] == EXPLORED) {
continue;
}
}
dfs_num[u] = EXPLORED;
}
const int INF = 1e18;
int32_t main() {
int n; cin >> n;
vector<int> arrmv;
for (int i = 0; i<n; i++) {
int t; cin >> t;
arrmv.push_back(t);
}
memset(bit, 0, sizeof(bit));
for (int i = 0; i<n; i++) {
int no = arrmv[i];
int bitcount = 0;
while (no) {
if (no & 1)bit[i][bitcount++] = 1;
no >>= 1;
}
}

set<int> poi;
for (int j = 0; j<65; j++) {
int count = 0;
int prev;
for (int i = 0; i<n; i++) {
if (bit[i][j] == 1) {
count++;
if (count == 1) {
prev = i;
continue;
}
if (count == 3) {
cout << 3 << endl;
exit(0);
}
if (count == 2) {
gra[prev].emplace_back(i);
gra[i].emplace_back(prev);
poi.insert(prev);
poi.insert(i);
}
}
}
}
int finans = INF;
for (auto it : poi) {

memset(dfs_num, UNVISITED, sizeof(dfs_num));
ans = INF;
dfs_find_circle(it, 0);
finans = min(ans, finans);
}
if (finans == INF)cout << -1 << endl;
else
cout << finans << endl;
return 0;
}