Submission #978206

#TimeUsernameProblemLanguageResultExecution timeMemory
978206model_codeSpy 3 (JOI24_spy3)C++17
100 / 100
81 ms7144 KiB
#include "Aoi.h"
#include <bits/stdc++.h>

using namespace std;

using ll = long long;

namespace {
    const ll linf = 1LL << 60;

    string encode(ll num, int len) {
        string s;
        for (int i = len - 1; i >= 0; i--) s.push_back('0' + (num >> i & 1));
        return s;
    }

    // {dist, pre}
    pair<vector<ll>, vector<int>> dijkstra(int n, const vector<int> &a, const vector<int> &b, const vector<ll> &c) {
        vector<vector<tuple<int, ll, int>>> G(n);
        for (int i = 0; i < a.size(); i++) {
            if (c[i] == -1) continue;
            G[a[i]].emplace_back(b[i], c[i], i);
            G[b[i]].emplace_back(a[i], c[i], i);
        }
        vector<ll> dist(n, linf);
        vector<int> pre(n, -1);
        priority_queue<pair<ll, int>, vector<pair<ll, int >>, greater<>> pq;
        dist[0] = 0;
        pq.emplace(0, 0);
        while (!pq.empty()) {
            auto [d, u] = pq.top();
            pq.pop();
            if (d > dist[u]) continue;
            for (auto [v, len, id]: G[u]) {
                if (dist[v] > d + len) {
                    dist[v] = d + len;
                    pre[v] = id;
                    pq.emplace(dist[v], v);
                }
            }
        }
        return {dist, pre};
    }
}

std::string aoi(int n, int m, int q, int k, std::vector<int> a,
                std::vector<int> b, std::vector<long long> c,
                std::vector<int> t, std::vector<int> x) {
    vector<int> x_id(m, -1);
    for (int i = 0; i < k; i++) x_id[x[i]] = i;
    auto [dist, pre] = dijkstra(n, a, b, c);
    vector<vector<int>> G(n + q);   // 最短路木
    for (int i = 1; i < n; i++) {
        G[a[pre[i]] ^ b[pre[i]] ^ i].push_back(i);
    }
    vector<int> bit(n);  // bit[i] : é ‚ç‚¹ i の subtree に含まれる t[j] たちの集合を 0 ~ (1<<q)-1 で
    for (int i = 0; i < q; i++) bit[t[i]] = 1 << i;
    auto dfs = [&](auto &dfs, int u) -> void {
        for (int v: G[u]) {
            dfs(dfs, v);
            bit[u] |= bit[v];
        }
    };
    dfs(dfs, 0);
    vector<int> s(k);
    for (int i = 0; i < k; i++) {
        int e = x[i];
        if (dist[a[e]] > dist[b[e]]) swap(a[e], b[e]);
        if (pre[b[e]] == e) {
            s[i] = bit[b[e]];
        }
    }
    sort(bit.begin(), bit.end());
    bit.erase(unique(bit.begin(), bit.end()), bit.end());
    // è¦ç´ æ•°ã®æ˜‡é †ã«ã‚½ãƒ¼ãƒˆ
    sort(bit.begin(), bit.end(), [](int a, int b) { return __builtin_popcount(a) < __builtin_popcount(b); });
    vector<pair<int, int>> div(1 << q);   // div[i] : 集合 i は何と何に分割されるか
    {
        set<int> st;
        for (int i = 0; i < q; i++) {
            st.insert(1 << i);
        }
        for (int i: bit) {
            if (!i) continue;
            vector<int> mg;
            for (int j: st) if ((j & i) == j) mg.push_back(j);
            for (int j = 1; j < mg.size(); j++) {
                int now = mg[j - 1] | mg[j];
                div[now] = {mg[j - 1], mg[j]};
                st.erase(mg[j - 1]);
                st.erase(mg[j]);
                st.insert(now);
                mg[j] = now;
            }
        }
    }
    vector binom(q, vector<ll>(q));
    for (int i = 0; i < q; i++) {
        binom[i][0] = 1;
        for (int j = 1; j <= i; j++) {
            binom[i][j] = binom[i - 1][j - 1] + binom[i - 1][j];
        }
    }
    vector<ll> dp(q + 1);   // dp[i] : {1, 2, ..., i} をいくつかの集合に分割する方法の数
    dp[1] = 1;
    for (int i = 2; i <= q; i++) {
        for (int j = 1; j < i; j++) {
            dp[i] += binom[i - 1][j - 1] * dp[j] * dp[i - j];
        }
    }
    vector<int> ls = {0};
    auto f = [&](auto &f, int now) -> ll {
        ls.push_back(now);
        int cnt = __builtin_popcount(now);
        if (cnt == 1) return 0;
        vector<int> fac;
        for (int i = 0; i < q; i++) if (now >> i & 1) fac.push_back(i);
        auto [l, r] = div[now];
        if (~l >> fac[0] & 1) swap(l, r);
        int lc = __builtin_popcount(l);
        int rc = __builtin_popcount(r);
        ll res = 0;
        for (int i = 1; i < lc; i++) {
            res += binom[cnt - 1][i - 1] * dp[i] * dp[cnt - i];
        }
        vector<int> nv;
        for (int i = 0; i < cnt; i++) {
            if (l >> fac[i] & 1) nv.push_back(0);
            else nv.push_back(1);
        }
        vector<int> v;
        for (int i = 0; i < lc; i++) v.push_back(0);
        for (int i = 0; i < rc; i++) v.push_back(1);
        do {
            if (v == nv) break;
            res += dp[lc] * dp[rc];
        } while (next_permutation(v.begin(), v.end()));
        ll lid = f(f, l);
        ll rid = f(f, r);
        res += lid * dp[rc] + rid;
        return res;
    };
    string res = encode(f(f, (1 << q) - 1), 53);
    for (int i = 0; i < k; i++) {
        res += encode(find(ls.begin(), ls.end(), s[i]) - ls.begin(), 5);
    }
    return res;
}
#include "Bitaro.h"
#include <bits/stdc++.h>

using namespace std;

namespace {
    using ll = long long;

    const ll linf = 1LL << 60;

    ll decode(string::iterator l, string::iterator r) {
        ll res = 0;
        while (l < r) {
            res *= 2;
            res += *l - '0';
            ++l;
        }
        return res;
    }

    // {dist, pre}
    pair<vector<ll>, vector<int>> dijkstra(int n, const vector<int> &a, const vector<int> &b, const vector<ll> &c) {
        vector<vector<tuple<int, ll, int>>> G(n);
        for (int i = 0; i < a.size(); i++) {
            if (c[i] == -1) continue;
            G[a[i]].emplace_back(b[i], c[i], i);
            G[b[i]].emplace_back(a[i], c[i], i);
        }
        vector<ll> dist(n, linf);
        vector<int> pre(n, -1);
        priority_queue<pair<ll, int>, vector<pair<ll, int >>, greater<>> pq;
        dist[0] = 0;
        pq.emplace(0, 0);
        while (!pq.empty()) {
            auto [d, u] = pq.top();
            pq.pop();
            if (d > dist[u]) continue;
            for (auto [v, len, id]: G[u]) {
                if (dist[v] > d + len) {
                    dist[v] = d + len;
                    pre[v] = id;
                    pq.emplace(dist[v], v);
                }
            }
        }
        return {dist, pre};
    }
}

void bitaro(int n, int m, int q, int k, std::vector<int> a, std::vector<int> b,
            std::vector<long long> c, std::vector<int> t, std::vector<int> x,
            std::string s) {
    vector binom(q, vector<ll>(q));
    for (int i = 0; i < q; i++) {
        binom[i][0] = 1;
        for (int j = 1; j <= i; j++) {
            binom[i][j] = binom[i - 1][j - 1] + binom[i - 1][j];
        }
    }
    vector<ll> dp(q + 1);   // dp[i] : {1, 2, ..., i} をいくつかの集合に分割する方法の数
    dp[1] = 1;
    for (int i = 2; i <= q; i++) {
        for (int j = 1; j < i; j++) {
            dp[i] += binom[i - 1][j - 1] * dp[j] * dp[i - j];
        }
    }
    vector<int> ls = {0};
    auto f = [&](auto &f, int now, ll val) -> void {
        ls.push_back(now);
        int cnt = __builtin_popcount(now);
        if (cnt == 1) return;
        vector<int> fac;
        for (int i = 0; i < q; i++) if (now >> i & 1) fac.push_back(i);
        int lc = 1;
        for (;; lc++) {
            ll cur = binom[cnt - 1][lc - 1] * dp[lc] * dp[cnt - lc];
            if (val < cur) break;
            val -= cur;
        }
        int rc = cnt - lc;
        vector<int> v;
        for (int i = 0; i < lc; i++) v.push_back(0);
        for (int i = 0; i < rc; i++) v.push_back(1);
        do {
            if (val < dp[lc] * dp[rc]) break;
            val -= dp[lc] * dp[rc];
        } while (next_permutation(v.begin(), v.end()));
        int l = 0, r = 0;
        for (int i = 0; i < cnt; i++) {
            if (!v[i]) l |= 1 << fac[i];
            else r |= 1 << fac[i];
        }
        f(f, l, val / dp[rc]);
        f(f, r, val % dp[rc]);
    };
    f(f, (1 << q) - 1, decode(s.begin(), s.begin() + 53));
    vector use(q, vector<bool>(k));
    int iter = 53;
    for (int i = 0; i < k; i++) {
        int bit = ls[decode(s.begin() + iter, s.begin() + iter + 5)];
        iter += 5;
        for (int j = 0; j < q; j++) if (bit >> j & 1) use[j][i] = true;
    }
    for (int i = 0; i < q; i++) {
        for (int j = 0; j < k; j++) {
            if (use[i][j]) c[x[j]] = 0;
        }
        auto [dist, pre] = dijkstra(n, a, b, c);
        int now = t[i];
        vector<int> es;
        while (now) {
            es.push_back(pre[now]);
            now = a[pre[now]] ^ b[pre[now]] ^ now;
        }
        reverse(es.begin(), es.end());
        answer(es);
        for (int j = 0; j < k; j++) c[x[j]] = -1;
    }
}

Compilation message (stderr)

Aoi.cpp: In function 'std::pair<std::vector<long long int>, std::vector<int> > {anonymous}::dijkstra(int, const std::vector<int>&, const std::vector<int>&, const std::vector<long long int>&)':
Aoi.cpp:20:27: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   20 |         for (int i = 0; i < a.size(); i++) {
      |                         ~~^~~~~~~~~~
Aoi.cpp: In function 'std::string aoi(int, int, int, int, std::vector<int>, std::vector<int>, std::vector<long long int>, std::vector<int>, std::vector<int>)':
Aoi.cpp:87:31: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   87 |             for (int j = 1; j < mg.size(); j++) {
      |                             ~~^~~~~~~~~~~

Bitaro.cpp: In function 'std::pair<std::vector<long long int>, std::vector<int> > {anonymous}::dijkstra(int, const std::vector<int>&, const std::vector<int>&, const std::vector<long long int>&)':
Bitaro.cpp:24:27: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   24 |         for (int i = 0; i < a.size(); i++) {
      |                         ~~^~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...