E-牛妹游历城市

题面链接

大致题意

给出 个节点的权值,如果两个点的权值 的结果不为 则认为这两个点之间有边相连,且边权为 求问从 走到 点,最短路径为多少

分析

首先不能暴力

因为点数有 个,所有可能的边的数量为

考虑位运算优化

我们准备出 32 个组,对于每一个值,如果这个值 在位置 上有值,即 则这个值划分至这个组中,规定每个值可以属于多个组

对于每个组,我们再定义一个变量表示到达组 中的值需要的边权价值

对于起点 ,我们考虑它的每一个位,如果位 上有值,则认为到达这个位置的组中的其他所有值需要花费 。记录下每个组的花费,然后对被遍历到的每一组中的每一个值进行类似起点的操作,类似 算法进行松弛,直到整个图没有发生更新花费

最后考虑最终点的每一位,找出花费最少的位并输出即可

注意特判起点和终点相同的时候

AC code

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

// NOLINTNEXTLINE
ll lowBit(ll x) { return x & (-x); }

void solve() {
    ll _;
    cin >> _;
    for (ll ts = 0; ts < _; ++ts) {
        ll n;
        cin >> n;
        vector<ll> data[40];
        vector<ll> cost(40, LONG_LONG_MAX);
        vector<ll> a(n);
        for (ll i = 0; i < n; ++i) {
            cin >> a[i];
            for (ll j = 0; j < 40; ++j)
                // NOLINTNEXTLINE
                if (a[i] & (1ll << j))
                    data[j].push_back(i);
        }
        if (n == 1) {
            cout << 0 << endl;
            continue;
        }
        queue<ll> q;
        for (ll i = 0; i < 40; ++i) {
            // NOLINTNEXTLINE
            if (a[0] & (1ll << i)) {
                q.push(i);
                // NOLINTNEXTLINE
                cost[i] = 1ll << i;
            }
        }

        while (!q.empty()) {
            ll cur = q.front();
            q.pop();
            for (auto item : data[cur]) {
                for (ll i = 0; i < 40; ++i) {
                    // NOLINTNEXTLINE
                    if ((a[item] & (1ll << i)) && cost[i] > (1ll << i) + cost[cur]) {
                        q.push(i);
                        // NOLINTNEXTLINE
                        cost[i] = (1ll << i) + cost[cur];
                    }
                }
            }
        }

        ll ans = LONG_LONG_MAX;
        for (ll i = 0; i < 40; ++i) {
            // NOLINTNEXTLINE
            if (a[n - 1] & (1ll << i)) {
                ans = min(ans, cost[i]);
            }
        }

        if (ans == LONG_LONG_MAX)
            cout << "Impossible" << endl;
        else
            cout << ans << endl;
    }
}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
#ifdef ACM_LOCAL
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    signed localTestCount = 1, localReadPos = cin.tellg();
    char localTryReadChar;
    do {
        if (localTestCount > 20)
            throw runtime_error("Check the stdin!!!");
        auto startClockForDebug = clock();
        solve();
        auto endClockForDebug = clock();
        cout << "Test " << localTestCount << " successful" << endl;
        cerr << "Test " << localTestCount++ << " Run Time: "
             << double(endClockForDebug - startClockForDebug) / CLOCKS_PER_SEC << "s" << endl;
        cout << "--------------------------------------------------" << endl;
    } while (localReadPos != cin.tellg() && cin >> localTryReadChar && localTryReadChar != '$' &&
             cin.putback(localTryReadChar));
#else
    solve();
#endif
    return 0;
}