牛客练习赛67 E
牛妹游历城市
https://ac.nowcoder.com/acm/contest/6885/E
E
题目大意
给定 个点,第
个点有权值
。如果对于
有
不为
,那么
间有无向边,边权为
。问从
到
的最短路。
题解
想了一个很憨的做法:依次考虑每一个位,对当前位建立一个新点,设为 。遍历所有点,如果点
满足这一位上为
,那么连一条从
到
的边,边权为这一位对应的二进制数;再连一条从
到
的边,边权为
。
然后跑 Dijkstra 即可。时间复杂度很高,但居然能过,我也是没想到的。
#include <bits/stdc++.h> #define REP(temp, init_val, end_val) for (int temp = init_val; temp <= end_val; ++temp) #define REPR(temp, init_val, end_val) for (int temp = init_val; temp >= end_val; --temp) using namespace std; typedef long long ll; int read(){ int f = 1, x = 0; char c = getchar(); while (c < '0' || c > '9'){if(c == '-') f = -f; c = getchar();} while (c >= '0' && c <= '9')x = x * 10 + c - '0', c = getchar(); return f * x; } int n; unsigned a[100005]; ll dis[100005 + 50]; priority_queue<pair<int, ll>, vector<pair<int, ll> >, greater<pair<int, ll> > > pq; int to[6400005], nxt[6400006], at[100005 + 50], cnt; unsigned w[6400005]; void init(){ n = read(); REP(i, 1, n) scanf("%u", &a[i]); // build graph memset(at, 0, sizeof(at)); cnt = 0; int nn = n; for (unsigned t = 1; t > 0; t <<= 1){ ++n; REP(i, 1, nn){ if (a[i] & t){ to[++cnt] = n, nxt[cnt] = at[i], w[cnt] = t, at[i] = cnt; to[++cnt] = i, nxt[cnt] = at[n], w[cnt] = 0, at[n] = cnt; } } } } void solve(){ memset(dis, 0x3f, sizeof(dis)); ll lim = dis[1]; dis[1] = 0; pq.push(make_pair(1, 0)); for (; ; ){ while (!pq.empty()){ if (pq.top().second > dis[pq.top().first]) pq.pop(); else break; } if (pq.empty()) break; int h = pq.top().first; ll dd = pq.top().second; pq.pop(); for (int i = at[h]; i; i = nxt[i]){ if (dd + w[i] < dis[to[i]]) dis[to[i]] = dd + w[i], pq.push(make_pair(to[i], dis[to[i]])); } } if (dis[n - 32] == lim){ printf("Impossible\n"); }else printf("%lld\n", dis[n - 32]); } int main(){ int T = read(); while (T--){ init(); solve(); } return 0; }