【牛客IOI周賽26-普及組 D-最短路 】題解
阿新 • • 發佈:2021-12-10
題目連結
題目
給定長度為 n 的數列 a,如果 (按位與),則在 i,j 之間存在一條長度為 的邊,求 1 至所有點的最短路。思路
暴力連邊,邊太多,最多 \(n^2\) 條,MLE+TLE。
於是考慮減少邊的數量。
首先建32個虛點。
然後加入 \(a_i\) 在第 \(k\) 位上為1,就在 \(i\) 和第 \(k\) 個虛點當中連邊,邊權為 \(a_i\)。
這樣最多有 \(n\times 32\) 條邊。
然後我們驗證一下,假如 \(a_i\& a_j\neq 0\),他們必有其中一位為都為1,經過兩條邊邊權分別為 \(a_i\) 和 \(a_j\)。
符合題意。
然後程式碼就很簡單了。
Code
// Problem: 最短路 // Contest: NowCoder // URL: https://ac.nowcoder.com/acm/contest/11233/D // Memory Limit: 524288 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org) #include<bits/stdc++.h> using namespace std; #define int long long inline int read(){int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+ (x<<3)+(ch^48);ch=getchar();}return x*f;} //#define mo #define N 200010 struct node { int x, y, z, n; }d[N*32]; int n, m, i, j, k; int ans[N], h[N], c[N], a[N]; int u, v, g; queue<int>q; void cun(int x, int y, int z) { // printf("%lld %lld %lld\n", x, y, z); d[++k].x=x; d[k].y=y; d[k].z=z; d[k].n=h[x]; h[x]=k; } signed main() { // freopen("tiaoshi.in","r",stdin); // freopen("tiaoshi.out","w",stdout); n=read(); for(i=1; i<=n; ++i) { a[i]=read(); for(int k=0; k<=32; ++k) if(a[i]&(1<<k)) cun(i, n+k+1, a[i]), cun(n+k+1, i, a[i]); } memset(ans, 0x3f, sizeof(ans)); ans[1]=0; q.push(1); while(!q.empty()) { u=q.front(); q.pop(); c[u]=0; for(g=h[u]; g; g=d[g].n) { v=d[g].y; if(ans[u]+d[g].z<ans[v]) { ans[v]=ans[u]+d[g].z; if(!c[v]) c[v]=1, q.push(v); } } } for(i=1; i<=n; ++i) printf("%lld ", (ans[i]==ans[0] ? -1 : ans[i])); return 0; }