E- 牛妹游历城市
一看n的范围果断放弃朴素的枚举每一对点求最短路的想法。
其实看到题目二进制,算法一般都和二进制沾边的。
可以把二进制的每个结点作为特别的中转站,所有结点连边可能的情况<=它二进制的位数,所以可以将后者作为连边的条件然后在取最短路的时候判断是不是有效的边就可以了,但是,本来是想在求最短路的时候加个判断来只有lowbit等于当前权值时进行放缩,后来想想没必要,因为两个结点有多个中转站可以走最短的那个肯定是lowbit那一个,所以直接最短路即可。
#include<queue>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<cmath>
/*#include<bits/stdc++.h> */
//#pragma GCC optimize(2)
using namespace std;
typedef long long LL;
inline LL read()
{
LL kk=0,f=1;
char cc=getchar();
while(cc<'0'||cc>'9'){if(cc=='-')f=-1;cc=getchar();}
while(cc>='0'&&cc<='9'){kk=(kk<<1)+(kk<<3)+cc-'0';cc=getchar();}
return kk*f;
}
void outLL(LL x)
{
if(x<0){x=~x+1;putchar('-');}
if(x>9)outLL(x/10);
putchar(char(x%10+'0'));
}const int maxn=100222;
const LL INF=1e18+7;
const LL mod=1000000007;
const double PI=acos(-1);
#define pii pair<LL,LL>
#define mp(x,y) make_pair(x,y)
vector<pii>edge[maxn];
LL n;
void add(LL a,LL b,LL w)
{
edge[a].push_back(mp(w,b));
edge[b].push_back(mp(w,a));
}
LL dis[maxn];
bool vis[maxn];
void diji()
{
for(int i=1;i<=n+35;++i)dis[i]=INF,vis[i]=0;
priority_queue<pii,vector<pii>,greater<pii> >Q;
dis[1]=0;
Q.push(mp(0,1));
while(!Q.empty())
{
LL disn,now;
now=Q.top().second;disn=Q.top().first;Q.pop();
if(vis[now])continue;
vis[now]=1;
for(auto to:edge[now])
{
if(!vis[to.second]&&dis[to.second]>dis[now]+to.first)
{
dis[to.second]=dis[now]+to.first;
Q.push(mp(dis[to.second],to.second));
}
}
}
}
int main()
{
int T=read();
while(T--)
{
n=read();
for(int i=0;i<=n+35;++i)edge[i].clear();
for(int i=1;i<=n;++i)
{
LL kk=read();
for(int j=0;j<32;++j)
{
if((kk>>j)&1)
{
add(i,n+1+j,(1ll<<j));
}
}
}
diji();
INF==dis[n]?printf("Impossible\n"):printf("%lld\n",dis[n]/2LL);
}
}