题目来源:https://codeforces.com/problemset/problem/1205/B
★这题真的非常可惜,我就差那么一点点就做出来了,可能还是自己太蒟蒻了…
题意:
有n个数,把他们看作是n个点。如果数a、b有 a&b不等于0,那么数a和数b所对应的点就可以相连。问 这n个数中,最短的环的长度是多少,没有就输出-1 。(长度一定要大于2)
思路:
首先我想,如果两个数a和b都是奇数,那么他们 一定相连,因为他们有共同的1。
接着 如果有 3个奇数,那不就可以成环了吗,而且不论n是多少,只要有3个奇数,最小环的长度一定是3
这还是远远不够的,上面思维 一直局限在最右边的二进制位
再仔细一想,不管二进制位的哪一个位上出现过3次1,那么不论n是多少,最小环的长度一定是3
数的范围是1e18,就是差不多有60个二进制位,num数组统计一下就好(60 x n)次循环基本搞定
上面是 特判,普通情况呢?
如果二进制位出现1的次数不能超过3,那意味着 二进制位数出现1次数为2 的才是我们需要的数(如果1出现一次绝对不行,自己可以想想) 满足条件的数的个数仅仅只有【数学排列组合,60个里面选2个】(60 x 59 / 2)约2000种? 其实不然,深入思考发现忽略了这个限制条件【二进制位出现1的次数为2】,所以 差不多只有60种的亚子?反正不超过200,已经有前人为你铺路了
然后问题就转化成了,有不超过200个数,问他们的最小环的长度是多少 这相当于模板题了吧~
一些废话:
这题是 Codeforces Round #580 (Div. 2) 的D题,当时只有500多个人写出来了,我就已经把下面的代码写出了99.9%,然后一直WA。比赛结束后第二天debug,发现 LL tmp=1ll<<j;
这个地方的1
没有加ll
,然后交了一发AC了。算了,吃一堑长一智啊,我不过是运气好罢了~
代码:
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<deque>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=1e5+5;
const int sz=1<<6;
const int inf=2e9;
const int mod=1e9+7;
const double pi=acos(-1);
typedef long long LL;
LL n,m;
LL f[maxn],g[maxn];
LL dis[200][200],mp[200][200];
int num[63],flag[maxn];
template<class T>
inline void read(T &x)
{
char c;x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
T res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
int main()
{
read(n);
int cnt=0;
memset(num,0,sizeof num);
for(int i=1;i<=n;i++){
read(f[i]);
flag[i]=0;
for(int j=0;j<=62;j++){
LL tmp=1ll<<j;
// cout<<tmp<<endl;
if(tmp&f[i]){
num[j]++; //数位j出现1的个数++
flag[i]++; //第i个数 的二进制数位1的个数++
}
}
}
// for(int i=0;i<=60;i++) cout<<i<<' '<<num[i]<<endl;
for(int i=0;i<=60;i++){ //特判
if(num[i]>=3) {cnt=1; break;}
}
if(cnt){cout<<"3\n"; return 0;}
cnt=0;
for(int i=1;i<=n;i++){ //让二进制数位出现1的次数为2的加入
if(flag[i]>=2){ // ==应该也可以
g[++cnt]=f[i];
}
}
for(int i=1;i<=cnt;i++){ //初始化两点间距离
for(int j=1;j<=cnt;j++){
dis[i][j]=1e9;
mp[i][j]=1e9;
if(i!=j){
if(g[i]&g[j]){
// cout<<i<<' '<<j<<endl;
dis[i][j]=1; mp[i][j]=1;
}
}
}
}
LL ans=1e9;
for(int k=1;k<=cnt;k++){ //floyed跑最小环
for(int i=1;i<k;i++)
for(int j=i+1;j<k;j++)
ans = min(ans,dis[i][j]+mp[i][k]+mp[k][j]);
for(int i=1;i<=cnt;i++)
for(int j=1;j<=cnt;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
if(ans==1e9) ans=-1;
cout<<ans<<endl;
return 0;
}