题目链接
题目大意
给你n(n<=1e5)个点,每个点有一个权值a[i],要你求从1到n的最短路
a[i]∩a[j]=0;dis[i][j]=0
a[i]∩a[j]!=0;dis[i][j]=lowbit(a[i]∩a[j])
题目思路
首先吐槽一下\(a[i]<2^{32}\) 这是ll级别的,\(int<2^{31}\)真毒瘤
这个题目利用了建虚点,对32个二进制位建立32个虚点,对于每个a[i],如果该二进制位j为1,那么连边权值为 1 << j。(注意虚点到该点的距离为0)
然后跑一个dij即可
你可能会问那这里跑的不就是所有的a[i]&a[j]的二进制位了嘛,而不是那个lowbit的那个二进制嘛
确实,但是你会发现这个是求最短路,那么最短路跑的必然是那个lowbit的那个二进制位
代码
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#define fi first
#define se second
#define debug printf(" I am here\n");
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,int> pii;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=1e5+50,inf=0x3f3f3f3f,mod=998244353;
const double eps=1e-10;
int n;
ll a[maxn];//int 2^31-1,要ll
int head[maxn],cnt;
ll dis[maxn];
struct edge{
int to,next;
ll w;
}e[maxn<<6];
void add(int u,int v,ll w){
e[++cnt]={v,head[u],w};
head[u]=cnt;
}
void init(){
cnt=0;
memset(head,0,sizeof(head));
}
void dij(int x){
priority_queue<pii,vector<pii>,greater<pii> > que;
memset(dis,0x3f,sizeof(dis));
dis[x]=0;
que.push({0,x});
while(!que.empty()){
int len=que.top().first;
int pos=que.top().second;
que.pop();
if(len<=dis[pos]){
for(int i=head[pos];i;i=e[i].next){
if(dis[e[i].to]>dis[pos]+e[i].w){
dis[e[i].to]=dis[pos]+e[i].w;
que.push({dis[e[i].to],e[i].to});//一定注意是len为fi
}
}
}
}
}
signed main(){
int _;scanf("%d",&_);
while(_--){
scanf("%d",&n);
init();
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
for(int j=0;j<=31;j++){
if(a[i]&(1ll<<j)){
add(i,n+j+1,(1ll<<j));//n+j+1为虚点
add(n+j+1,i,0);
}
}
}
dij(1);
if(dis[n]==INF){
printf("Impossible\n");
}else{
printf("%lld\n",dis[n]);
}
}
return 0;
}