Submission #1062173

#TimeUsernameProblemLanguageResultExecution timeMemory
1062173j_vdd16Flights (JOI22_flights)C++17
0 / 100
38 ms3544 KiB
#include "Ali.h"

#include <algorithm>
#include <bitset>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <limits.h>
#include <math.h>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>

//#define int long long
#define loop(X, N) for(int X = 0; X < (N); X++)
#define all(V) V.begin(), V.end()
#define rall(V) V.rbegin(), V.rend()

using namespace std;

typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<int, int> ii;
typedef vector<ii> vii;
typedef vector<vector<ii>> vvii;
typedef vector<bool> vb;
typedef vector<vector<bool>> vvb;

namespace {

    int n;
    vvi adj;

    priority_queue<ii> specialQueue;
    vi specialIndices;
    vi subtreeSizes;
    vb isSpecial;
    vii inOut;
    vvi children;
    int counter;

    constexpr int MAX_GROUP_COUNT = 1446;
    constexpr int BEST = 10000 / MAX_GROUP_COUNT;
    constexpr int MAX = 2 * (10000 / MAX_GROUP_COUNT) - 1;

    // ii divideDfs(int node, int parent, int splitLim) {
    //     int subtreeSize = 1;
    //     int count = 0;

    //     for (int child : adj[node]) {
    //         if (child == parent) continue;

    //         ii res = divideDfs(child, node, splitLim);
    //         subtreeSize += res.first;
    //         count += res.second;
    //     }

    //     if (subtreeSize >= splitLim) {
    //         count++;
    //         subtreeSize = 0;
    //     }

    //     return { subtreeSize, count };
    // }
    int dfs(int node, int parent, int splitLim) {
        inOut[node].first = counter++;

        int subtreeSize = 1;

        for (int child : adj[node]) {
            if (child == parent) continue;

            subtreeSize += dfs(child, node, splitLim);
            children[node].push_back(child);
        }

        inOut[node].second = counter++;

        subtreeSizes[node] = subtreeSize;
        if (subtreeSize > MAX) {
            isSpecial[children[node][0]] = true;
            isSpecial[children[node][1]] = true;

            subtreeSizes[node] = 1;
            subtreeSize = 1;
        }
        else if (subtreeSize >= splitLim) {
            isSpecial[node] = true;
            subtreeSize = 0;
        }

        return subtreeSize;
    }
    void split(int node) {
        vi possible;
        for (int child : children[node]) {
            if (isSpecial[child]) continue;

            possible.push_back(child);
        }

        int child;
        if (possible.size() == 2) { 
            if (subtreeSizes[possible[0]] > subtreeSizes[possible[1]]) {
                child = possible[0];
            }
            else {
                child = possible[1];
            }
        }
        else {
            child = possible[0];
        }

        isSpecial[child] = true;
        specialQueue.push({subtreeSizes[child], child});
        subtreeSizes[node] -= subtreeSizes[child];
        specialQueue.push({subtreeSizes[node], node});
    }

    bool isAncestor(int a, int b) {
        return inOut[a].first <= inOut[b].first && inOut[b].first <= inOut[a].second;
    }
    
    int maxGroupSize = 0;
    int minGroupSize = INT_MAX;
    void dfsID(int node, int specialIndex, int& count) {
        SetID(node, specialIndex * MAX + (count++));
        
        if (children[node].size() == 2) {
            if (subtreeSizes[children[node][0]] < subtreeSizes[children[node][1]])
                swap(children[node][0], children[node][1]);
        }

        for (int child : children[node]) {
            if (isSpecial[child]) continue;

            dfsID(child, specialIndex, count);
        }
    }
    void setIDS() {
        loop(i, specialIndices.size()) {
            int count = 0;
            dfsID(specialIndices[i], i, count);
        }
    }
    
    vi catalan, catPref;
    vvi catPref2;
    void initCatalan() {
        catalan = vi(MAX + 1);
        catalan[0] = 1;

        catPref = vi(MAX + 2);
        catPref2 = vvi(MAX + 1, vi(MAX + 1));
        for (int i = 1; i <= MAX; i++) {
            for (int j = (i - 1) / 2; j >= 0; j--) {
                catPref2[i][i - 1 - j] = catalan[i];

                if (i - 1 - j >= BEST || j >= BEST) 
                    continue;

                if (i - 1 - j == j) {
                    catalan[i] += catalan[i - 1 - j] * catalan[j];
                    //catalan[i] += catalan[j] * (catalan[j] + 1) / 2;
                }
                else {
                    catalan[i] += catalan[i - 1 - j] * catalan[j];
                }
            }

            catPref[i] = catPref[i - 1] + catalan[i - 1];
            //pref2[i][j] = cat[j - k] * cat[i - 1 - (j - k)]
        }
        catPref[MAX + 1] = catPref[MAX] + catalan[MAX];
    }
    int catalanCompress(int node) {
        int childCount = 0;
        vi relevant;
        for (int child : children[node]) {
            if (isSpecial[child]) continue;

            childCount++;
            relevant.push_back(child);
        }

        if (relevant.size() == 0) return 0;
            
        int child0 = relevant[0];

        int cat1 = catalanCompress(child0);
        int cat2 = 0;
        if (relevant.size() == 2) {
            cat2 = catalanCompress(relevant[1]);
        }

        int size0 = subtreeSizes[child0];

        int res = catPref2[subtreeSizes[node]][size0] + cat1 * catalan[subtreeSizes[node] - size0 - 1] + cat2;
        return res;
    }
}

void Init(int N, std::vector<int> U, std::vector<int> V) {
    initCatalan();

    n = N;
    adj = vvi(n);
    loop(i, n - 1) {
        adj[U[i]].push_back(V[i]);
        adj[V[i]].push_back(U[i]);
    }

    specialIndices = vi();
    subtreeSizes = vi(n);
    isSpecial = vb(n);
    counter = 0;
    inOut = vii(n);
    children = vvi(n);

    int root = 0;
    if (adj[0].size() > 2) {
        loop(i, n) {
            if (adj[i].size() <= 2) root = i;
        }
    }
    cerr << "Root: " << root << endl;

    dfs(root, root, BEST);
    if (!isSpecial[root]) {
        isSpecial[root] = true;
    }

    loop(i, n) {
        if (isSpecial[i]) {
            specialQueue.push({subtreeSizes[i], i});
        }
    }

    while (specialQueue.size() < min(MAX_GROUP_COUNT, (2 * n + 20) / MAX)) {
        auto [size, node] = specialQueue.top();

        specialQueue.pop();
        split(node);
    }

    while (specialQueue.size()) {
        specialIndices.push_back(specialQueue.top().second);
        specialQueue.pop();
    }

    for (int x : specialIndices) {
        maxGroupSize = max(maxGroupSize, subtreeSizes[x]);
        minGroupSize = min(minGroupSize, subtreeSizes[x]);
    }
    cerr << "Max group size: " << maxGroupSize << endl;
    cerr << "Min group size: " << minGroupSize << endl;

    setIDS();
}

namespace {

    int distanceDfs(int node, int parent, int goal) {
        if (node == goal) return 0;

        for (int child : adj[node]) {
            if (child == parent) continue;

            int res = distanceDfs(child, node, goal);
            if (res >= 0) return res + 1;
        }

        return -1;
    }
    void treeCode(int node, string& code) {
        int childCount = 0;
        for (int child : children[node]) {
            if (isSpecial[child]) continue;

            childCount++;
            code.push_back('1');

            treeCode(child, code);
        }

        if (childCount < 2)
            code.push_back('0');
    }

    ii closestLeafDfs(int node, const vi& distances, int& closestCounter) {
        ii best = { node, closestCounter++ };
        
        for (int child : children[node]) {
            if (isSpecial[child]) continue;

            ii res = closestLeafDfs(child, distances, closestCounter);
            if (distances[res.first] < distances[best.first]) 
                best = res;
        }

        return best;
    }

    void setDistances(int node, int parent, int distance, vi& distances) {
        distances[node] = distance;

        for (int child : adj[node]) {
            if (child == parent) continue;

            setDistances(child, node, distance + 1, distances);
        }
    }
}

std::string SendA(std::string S) { //return max 24 is optimal
    int inCode = 0;
    loop(i, 20) {
        if (S[i] == '1') inCode += 1 << i;
    }

    int idx1 = 0;
    while ((idx1 + 1) * idx1 / 2 <= inCode) idx1++;
    idx1--;

    int idx2 = inCode - (idx1 + 1) * idx1 / 2;

    // int idx1 = 0, idx2 = 0;
    // loop(i, 10) {
    //     idx1 += (S[i] == '1') * (1 << i);
    // }
    // loop(i, 10) {
    //     idx2 += (S[i + 10] == '1') * (1 << i);
    // }
    int node1 = specialIndices[idx1];
    int node2 = specialIndices[idx2];

    int bitCount = 0;
    {
        int count = catPref[MAX + 1];
        while (count) {
            bitCount++;
            count /= 2;
        }
    }

    string code1(bitCount, '0'), code2(bitCount, '0');
    {
        int cat1 = catPref[subtreeSizes[node1]] + catalanCompress(node1);
        int cat2 = catPref[subtreeSizes[node2]] + catalanCompress(node2);

        loop(i, bitCount) {
            if (cat1 & (1 << i)) code1[i] = '1';
            if (cat2 & (1 << i)) code2[i] = '1';
        }
    }
    
    cerr << "Code 1: " << code1 << endl;
    cerr << "Code 2: " << code2 << endl;

    if (node1 == node2) {
        int dist = distanceDfs(node1, -1, node2);
        string result(14, '0');
        loop(i, 14) {
            if (dist & (1 << i)) result[i] = '1';
        }

        return result + code1;
    }

    string extra;
    if (isAncestor(node1, node2)) {
        vi distances(n);
        setDistances(node2, -1, 0, distances);

        int closestCounter = 0;
        ii closest = closestLeafDfs(node1, distances, closestCounter);
        extra += "0";

        node1 = closest.first;
        while (closest.second) {
            if (closest.second % 2) 
                extra.push_back('1');
            else 
                extra.push_back('0');

            closest.second /= 2;
        }
    }
    else if (isAncestor(node2, node1)) {
        vi distances(n);
        setDistances(node1, -1, 0, distances);

        int closestCounter = 0;
        ii closest = closestLeafDfs(node2, distances, closestCounter);
        extra += "1";

        node2 = closest.first;
        while (closest.second) {
            if (closest.second % 2) 
                extra.push_back('1');
            else 
                extra.push_back('0');

            closest.second /= 2;
        }
    }

    int dist = distanceDfs(node1, -1, node2);
    string result(14, '0');
    loop(i, 14) {
        if (dist & (1 << i)) result[i] = '1';
    }

    return result + code1 + code2 + extra;
}
#include "Benjamin.h"

#include <algorithm>
#include <bitset>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <limits.h>
#include <math.h>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>

//#define int long long
#define loop(X, N) for(int X = 0; X < (N); X++)
#define all(V) V.begin(), V.end()
#define rall(V) V.rbegin(), V.rend()

using namespace std;

typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<int, int> ii;
typedef vector<ii> vii;
typedef vector<vector<ii>> vvii;
typedef vector<bool> vb;
typedef vector<vector<bool>> vvb;

namespace {

    int x, y;

    constexpr int MAX_GROUP_COUNT = 1446;
    constexpr int BEST = 10000 / MAX_GROUP_COUNT;
    constexpr int MAX = 2 * (10000 / MAX_GROUP_COUNT) - 1;

    vi catalan, catPref;
    vvi catPref2;
    void initCatalan() {
        catalan = vi(MAX + 1);
        catalan[0] = 1;

        catPref = vi(MAX + 2);
        catPref2 = vvi(MAX + 1, vi(MAX + 1));
        for (int i = 1; i <= MAX; i++) {
            for (int j = (i - 1) / 2; j >= 0; j--) {
                catPref2[i][i - 1 - j] = catalan[i];
                
                if (i - 1 - j >= BEST || j >= BEST) 
                    continue;

                if (i - 1 - j == j) {
                    catalan[i] += catalan[i - 1 - j] * catalan[j];
                    //catalan[i] += catalan[j] * (catalan[j] + 1) / 2;
                }
                else {
                    catalan[i] += catalan[i - 1 - j] * catalan[j];
                }
            }

            catPref[i] = catPref[i - 1] + catalan[i - 1];
            //pref2[i][j] = cat[j - k] * cat[i - 1 - (j - k)]
        }
        catPref[MAX + 1] = catPref[MAX] + catalan[MAX];
    }
}

std::string SendB(int N, int X, int Y) {
    initCatalan();
    cerr << "X: " << X << ", Y: " << Y << endl;

    x = X;
    y = Y;

    X /= MAX;
    Y /= MAX;

    if (X < Y) {
        swap(X, Y);
        swap(x, y);
    }

    /*
    0, 0 = 0
    1, 0 = 1
    1, 1 = 2
    2, 0 = 3
    2, 1 = 4
    */
    int out = ((X + 1) * X) / 2 + Y;

    string outStr(20, '0');
    loop(i, 20) {
        if (out & (1 << i)) outStr[i] = '1';
    }

    return outStr;

    //log2(N) < 14

    // string out(20, '0');
    // loop(i, 10) {
    //     if (X & (1 << i)) out[i] = '1';
    // }
    // loop(i, 10) {
    //     if (Y & (1 << i)) out[10 + i] = '1';
    // }

    // return out;
}

namespace {
    void catalanDecompressDfs(int node, vii& children, vi& parents, vvi& adj, int code, int size) {
        int size0 = (size - 1) / 2;
        for (; size0 < size; size0++) {
            if (catPref2[size][size0] > code) break;
        }
        size0--;

        code -= catPref2[size][size0];
        int code0 = code / catalan[size - size0 - 1];
        int code1 = code % catalan[size - size0 - 1];

        if (size0 == 0) 
            return;

        int child0 = (int)children.size();
        
        children[node].first = child0;
        adj.push_back({});
        adj[child0] = { node };
        adj[node].push_back(child0);

        children.push_back({-1, -1});
        parents.push_back(node);

        catalanDecompressDfs(child0, children, parents, adj, code0, size0);
        if (size - size0 - 1 > 0) {
            int child1 = (int)children.size();

            children[node].second = child1;
            adj.push_back({});
            adj[children.size()] = { node };
            adj[node].push_back(child1);

            children.push_back({-1, -1});
            parents.push_back(node);

            catalanDecompressDfs(child1, children, parents, adj, code1, size - size0 - 1);
        }

        // int res = catPref2[subtreeSizes[node]][size0] + cat1 * catalan[subtreeSizes[node] - size0 - 1] + cat2;
    }
    void catalanDecompress(vii& children, vi& parents, vvi& adj, const string& T) {
        int code = 0;
        loop(i, (int)T.size()) {
            if (T[i] == '1')
                code += 1 << i;
        }

        int nodeCount = 1;
        while (code >= catPref[nodeCount]) 
            nodeCount++;
        
        nodeCount--;
        code -= catPref[nodeCount];

        children = { {-1, -1} };
        parents = { 0 };
        adj = { {} };

        catalanDecompressDfs(0, children, parents, adj, code, nodeCount);
    }

    int distanceDfs(const vvi& adj, int node, int parent, int goal) {
        if (node == goal) return 0;

        for (int child : adj[node]) {
            if (child == parent) continue;

            int res = distanceDfs(adj, child, node, goal);
            if (res >= 0) return res + 1;
        }

        return -1;
    }
}

int Answer(std::string T) {
    cerr << "T: " << T << endl;

    int dist = 0;
    int i = 0;
    for (; i < 14; i++) {
        if (T[i] == '1')
            dist += (1 << i);
    }

    cerr << "Dist: " << dist << endl;
    cerr << "Rest: " << T.substr(i) << endl;

    int node1 = x % (MAX);
    int node2 = y % (MAX);

    vii children1, children2;
    vi parents1, parents2;
    vvi adj1, adj2;

    int bitCount = 0;
    {
        int count = catPref[MAX + 1];
        while (count) {
            bitCount++;
            count /= 2;
        }
    }
    
    catalanDecompress(children1, parents1, adj1, T.substr(i, bitCount));
    i += bitCount;

    if (x / MAX == y / MAX) {
        return distanceDfs(adj1, node1, -1, node2);
    }

    catalanDecompress(children2, parents2, adj2, T.substr(i, bitCount));
    i += bitCount;

    int start1 = 0, start2 = 0;
    if (i < (int)T.size()) {
        bool nextBit = T[i++] == '1';
        
        int closestIdx = 0;
        int startIdx = i;
        while (i < T.size()) {
            closestIdx += (T[i] == '1') * (1 << (i - startIdx));
            i++;
        }

        if (nextBit) {
            start2 = closestIdx;
        }
        else {
            start1 = closestIdx;
        }
    }

    dist += distanceDfs(adj1, start1, -1, node1);
    dist += distanceDfs(adj2, start2, -1, node2);

    return dist;
}

Compilation message (stderr)

Ali.cpp: In function 'void {anonymous}::setIDS()':
Ali.cpp:19:37: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   19 | #define loop(X, N) for(int X = 0; X < (N); X++)
      |                                     ^
Ali.cpp:146:9: note: in expansion of macro 'loop'
  146 |         loop(i, specialIndices.size()) {
      |         ^~~~
Ali.cpp: In function 'void Init(int, std::vector<int>, std::vector<int>)':
Ali.cpp:244:32: warning: comparison of integer expressions of different signedness: 'std::priority_queue<std::pair<int, int> >::size_type' {aka 'long unsigned int'} and 'const int' [-Wsign-compare]
  244 |     while (specialQueue.size() < min(MAX_GROUP_COUNT, (2 * n + 20) / MAX)) {
      |            ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
grader_ali.cpp:10:8: warning: '{anonymous}::_randmem' defined but not used [-Wunused-variable]
   10 |   char _randmem[12379];
      |        ^~~~~~~~

Benjamin.cpp: In function 'int Answer(std::string)':
Benjamin.cpp:238:18: warning: comparison of integer expressions of different signedness: 'int' and 'std::__cxx11::basic_string<char>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  238 |         while (i < T.size()) {
      |                ~~^~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...