Submission #49586

#TimeUsernameProblemLanguageResultExecution timeMemory
49586model_codeKoala Game (APIO17_koala)C++17
92 / 100
145 ms848 KiB
#include "koala.h"
#include <bits/stdc++.h>
using namespace std;

#define FO(i,a,b) for (int i = (a); i < (b); i++)
#define pb push_back
#define sz(v) ((int)v.size())

struct Query {
    vector <int> am;
};

struct Response {
    vector <bool> v;
};

int N, W;

Response makeQuery (Query q) {
    int *B = (int *)malloc(sizeof(int)*N);
    FO (i,0,N) B[i] = q.am[i];
    int *R = (int *)malloc(sizeof(int)*N);
    playRound(B,R);
    Response r;
    FO (i,0,N) {
        if (R[i] > B[i]) {
            r.v.pb(true);
        } else {
            r.v.pb(false);
        }
    }
    free(B);
    free(R);
    return r;
}

Response makeUniformQuery (set<int> &cand, int am) {
    Query q;
    FO (i,0,N) {
        if (cand.find(i) != cand.end()) {
            q.am.pb(am);
        } else {
            q.am.pb(0);
        }
    }
    return makeQuery(q);
}

set<int> responseToSet (Response r) {
    set <int> s;
    FO (i,0,N) if (r.v[i]) s.insert(i);
    return s;
}

int minValue(int _N, int _W) {
    N = _N; W = _W;
    set <int> cand;
    cand.insert(0);
    Response r = makeUniformQuery(cand, 1);
    FO (i,0,N) {
        if (!r.v[i]) return i;
    }
    assert (false);
}

int actualGetMax() {
    set <int> cand;
    FO (i,0,N) cand.insert(i);
    while (cand.size() > 1) {
        Response r = makeUniformQuery(cand, W/(int)cand.size());
        set <int> newC;
        FO (i,0,N) if (cand.find(i) != cand.end() && r.v[i]) newC.insert(i);
        cand = newC;
    }
    return *(cand.begin());
}

int maxValue(int _N, int _W) {
    N = _N; W = _W;
    return actualGetMax();
}

int greaterValue(int _N, int _W) {
    N = _N; W = _W;
    set <int> f2 = {0,1};
    int cands[4] = {1,3,6,8};
    int lo = 0;
    int hi = 3;
    int mid;
    while (lo <= hi) {
        mid = (lo+hi)/2;
        Response r = makeUniformQuery(f2, cands[mid]);
        set <int> origRes = responseToSet(r);
        set <int> res;
        for (auto c : f2) {
            if (origRes.find(c) != origRes.end()) res.insert(c);
        }
        switch (res.size()) {
            case 0:
                hi = mid-1;
                break;
            case 1:
                return *(res.begin());
            case 2:
                lo = mid+1;
                break;
        }
    }
    assert(false);
}

vector <int> sortRange (vector <int> vals);
void solveMain(int *P);
void allValues(int _N, int _W, int *P) {
    N = _N; W = _W;
    if (_W == 2*_N) {
        vector <int> startVals;
        FO (i,0,N) startVals.pb(i);
        vector <int> endVals = sortRange(startVals);
        FO (i,0,N) P[endVals[i]] = N-i;
    } else {
        solveMain(P);
    }
}

// returns greater of the 2
int sub4cmp(int a, int b) {
    set<int> vals = {a,b};
    set<int> takens = responseToSet(makeUniformQuery(vals, W/2));
    if (takens.find(a) != takens.end()) return a;
    else return b;
}

vector <int> sortRange (vector <int> vals) {
    if (vals.size() == 1) return vals;
    vector <int> fV, sV;
    FO (i,0,sz(vals)) {
        if (i%2) sV.pb(vals[i]);
        else fV.pb(vals[i]);
    }
    vector <int> sF = sortRange(fV);
    vector <int> sS = sortRange(sV);
    int fI(0), sI(0);
    vector <int> retV;
    while (fI < sz(sF) || sI < sz(sS)) {
        if (fI == sz(sF)) retV.pb(sS[sI++]);
        else if (sI == sz(sS)) retV.pb(sF[fI++]);
        else {
            if (sub4cmp(sF[fI], sS[sI]) == sF[fI]) {
                retV.pb(sF[fI++]);
            } else {
                retV.pb(sS[sI++]);
            }
        }
    }
    return retV;
}

set <int> lowestVals;
#define N_BUCKETS 9
#define B_SIZ 10
vector <int> startBuckets[N_BUCKETS];
vector <int> sortedB[N_BUCKETS];
int valToPos[105];

int maxInSet(set<int> &s) {
    // Need this:
    assert(s.size() <= 9);
    set<int> qSet(s);
    for (int i = 10; i >= 1; i--) {
        if (qSet.size() == 9) break;
        qSet.insert(valToPos[i]);
    }
    set<int> taken;
    if (s.size() == 1) {
        taken = responseToSet(makeUniformQuery(qSet, 10));
    } else {
        taken = responseToSet(makeUniformQuery(qSet, 11));
    }
    for (int v : s) {
        if (taken.find(v) != taken.end()) return v;
    }
    assert(false);
}

void solveMain (int *P) {
    lowestVals.clear();
    FO (i,0,N_BUCKETS) {
        startBuckets[i].clear();
        sortedB[i].clear();
    }
    int mx = actualGetMax();
    set<int> mxSet({mx});
    set<int> notLowestVals = 
        responseToSet(makeUniformQuery(mxSet, 10));
    FO (i,0,N) {
        if (notLowestVals.count(i) == 0) lowestVals.insert(i);
    }
    assert(lowestVals.size() == 10);
    FO (i,0,N) {
        if (lowestVals.find(i) != lowestVals.end()) continue;
        FO (b,0,N_BUCKETS) {
            if (startBuckets[b].size() < B_SIZ) {
                startBuckets[b].pb(i);
                break;
            }
        }
    }
    // Get bottom 10:
    set <int> lowLeft (lowestVals);
    while (lowLeft.size()) {
        if (lowLeft.size() == 1) {
            valToPos[1] = *lowLeft.begin();
            break;
        }
        set <int> res =
            responseToSet(makeUniformQuery(lowLeft, lowLeft.size()-1));
        for (int v : res) {
            if (lowLeft.find(v) != lowLeft.end()) {
                valToPos[lowLeft.size()] = v;
                lowLeft.erase(v);
                break;
            }
        }
    }
    FO (b,0,N_BUCKETS) {
        set <int> remThings(startBuckets[b].begin(), startBuckets[b].end());
        while (remThings.size()) {
            if (remThings.size() == 10) {
                // one special case:
                set <int> res = responseToSet(makeUniformQuery(remThings, 10));
                set <int> cMax;
                for (int v : res) {
                    if (remThings.find(v) != remThings.end()) {
                        cMax.insert(v);
                    }
                }
                if (cMax.size() == 2) {
                    int mx = maxInSet(cMax);
                    sortedB[b].pb(mx);
                    cMax.erase(mx);
                    sortedB[b].pb(*cMax.begin());
                    remThings.erase(mx);
                    remThings.erase(*cMax.begin());
                } else if (cMax.size() == 1) {
                    sortedB[b].pb(*cMax.begin());
                    remThings.erase(*cMax.begin());
                } else {
                    assert(false);
                }
            } else {
                int mx;
                if (remThings.size() == 1) mx = *remThings.begin();
                else mx = maxInSet(remThings);
                sortedB[b].pb(mx);
                remThings.erase(mx);
            }
        }
    }
    // Merge buckets:
    // Sort buckets into increasing order not decreasing:
    FO (i,0,N_BUCKETS) reverse(sortedB[i].begin(), sortedB[i].end());
    vector <int> sortedAll;
    while(true) {
        set <int> cFronts;
        FO (i,0,N_BUCKETS) {
            if (sortedB[i].size()) {
                cFronts.insert(sortedB[i].back());
            }
        }
        if (cFronts.empty()) break;
        int mx = maxInSet(cFronts);
        sortedAll.pb(mx);
        FO (i,0,N_BUCKETS) {
            if (sortedB[i].size() && sortedB[i].back() == mx) {
                sortedB[i].pop_back();
            }
        }
    }
    for (int i = 10; i >= 1; i--) {
        sortedAll.pb(valToPos[i]);
    }
    FO (i,0,sz(sortedAll)) {
        P[sortedAll[i]] = N-i;
    }
}

#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...