满分做法:
因为每个数都小于\(10^{18}\),因此每个数最多有\(64\)位,因此如果有超过\(128\)个非零数字,那么必定有一位在\(3\)个及以上个数的二进制表示下为\(1\),所以最小环大小为\(3\)。
当n<=128时,直接Floyd判最小环。
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
typedef long long ll;
const int maxm=1e5+7;
int n;
ll a[maxm];
int dis[133][133];
int len[133][132];
int ans=1e9+7;
void Floyd()
{
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
if(i==j||i==k||j==k) continue;
ans=min((ll)ans,(ll)dis[i][j]+(ll)len[i][k]+(ll)len[k][j]);
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
}
int main()
{
memset(dis,63,sizeof(dis));
memset(len,63,sizeof(len));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
if(!a[i]) n--,i--;//注意a[i]==0时必不会有连边,直接去除,使剩下的达到128
}
if(n>=128)
printf("3\n");
else
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if((a[i]&a[j])!=0&&i!=j)
len[i][j]=dis[j][i]=1;
}
}
Floyd();
if(ans==1e9+7)
printf("-1\n");
else
printf("%d\n",ans);
}
return 0;
}