输入
2 6 2 3 5 8 13 21 12 1 2 3 4 5 6 7 8 9 10 11 12
输出
3 5示例2
输入
5 3 1 2 3 4 177 188 199 211 2 1 2 4 1 1 1 1 5 1 2 4 8 16
输出
1 1 Impossible 1 Impossible
第一次遇到建虚点做中介的题(绝不是因为是个废物而懒得刷题)。首先考虑暴力建路径,n2的复杂度明显超时。考虑二进制优化,对32个二进制位建32个虚点,对于每个点如果该点二进制第 j 位为1,则该点的与虚点的边权值为 1<<j。虚点指向实点的边权为 0。 跑一个最后dijkstra即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int qs=1e5+500; 5 const ll inf=1e18; 6 ll T,n,d[qs]; 7 bool u[qs]; 8 struct node{ 9 int y; ll p; 10 node(){} 11 node(int y,ll p):y(y),p(p){}; 12 /*bool operator < (const node &tem) const{ 13 return y>tem.y; 14 }*/ 15 // 本来想重载运算符将优先队列变成小根对,出了点问题 qwq 16 }t; 17 18 vector<node> vc[qs]; // 不会链式前向星 qwq 19 priority_queue<pair <ll,int > > q; 20 21 void dijkstra(){ 22 q.push(make_pair(0,1)); 23 while(q.size()){ 24 int x=q.top().second; q.pop(); //取出堆顶 25 if(u[x]) continue; u[x]=true; 26 for(int i=0;i<vc[x].size();++i){ //访问每一个相邻节点 27 int y=vc[x][i].y;ll p=vc[x][i].p; 28 if(d[y]>d[x]+p){ 29 d[y]=d[x]+p; //更新最短路 30 q.push(make_pair(-d[y],y)); //pair第一维dist相反数,变成小根堆 31 } 32 } 33 } 34 } 35 int main(){ 36 cin>>T; 37 while(T--){ 38 cin>>n; ll fx; 39 // 初始化 40 for(int i=0;i<=n+200;++i) d[i]=inf,vc[i].clear(); d[1]=0; 41 memset(u,false,sizeof(u)); 42 for(int i=1;i<=n;++i){ 43 cin>>fx; 44 for(int j=0;j<=31;++j){ 45 if(fx & (1ll<<j)){ //与虚点建边 46 ll a=1ll<<j; 47 vc[i].push_back(node(n+j+1,a)); 48 vc[n+1+j].push_back(node(i,0)); 49 } 50 } 51 } 52 dijkstra(); 53 if(d[n]>=inf) cout<<"Impossible\n"; 54 else cout<<d[n]<<"\n"; 55 } 56 return 0; 57 }
//老废宅了.jpg
it(5)=lowbit((101)2)=1, lowbit(8)=lowbit((1000)2)=8