#include <algorithm>
#include <array>
#include <chrono>
#include <cstdint>
#include <cstdio>
#include <numeric>
#include <unordered_set>
#include <vector>

using namespace std;

struct XorShift {
    uint64_t s;
    explicit XorShift(uint64_t seed) : s(seed ? seed : 1) {}
    uint64_t next() {
        uint64_t x = s;
        x ^= x << 7;
        x ^= x >> 9;
        return s = x;
    }
    int randint(int n) { return (int)(next() % (uint64_t)n); }
};

static vector<array<pair<int,int>,12>> cube_patterns() {
    vector<pair<int,int>> ce;
    for (int x = 0; x < 8; ++x) for (int b = 0; b < 3; ++b) {
        int y = x ^ (1 << b);
        if (x < y) ce.push_back({x,y});
    }
    array<int,8> p{};
    iota(p.begin(), p.end(), 0);
    unordered_set<string> seen;
    vector<array<pair<int,int>,12>> out;
    do {
        array<pair<int,int>,12> es{};
        for (int i = 0; i < 12; ++i) {
            int a = p[ce[i].first], b = p[ce[i].second];
            if (a > b) swap(a,b);
            es[i] = {a,b};
        }
        sort(es.begin(), es.end());
        string k;
        for (auto [a,b] : es) { k += char('0'+a); k += char('0'+b); }
        if (seen.insert(k).second) out.push_back(es);
    } while (next_permutation(p.begin(), p.end()));
    return out;
}

static int edge_var(int n, int a, int b) {
    if (a > b) swap(a,b);
    return a * n - a * (a + 1) / 2 + (b - a) - 1;
}

int main(int argc, char **argv) {
    int n = argc > 1 ? atoi(argv[1]) : 13;
    int vars = n * (n - 1) / 2;
    auto pats = cube_patterns();
    vector<array<int,12>> clauses;
    vector<int> verts(n);
    iota(verts.begin(), verts.end(), 0);
    vector<int> mask(n, 0);
    fill(mask.begin(), mask.begin() + 8, 1);
    sort(mask.begin(), mask.end(), greater<int>());
    do {
        vector<int> sub;
        for (int i = 0; i < n; ++i) if (mask[i]) sub.push_back(i);
        for (auto &pat : pats) {
            array<int,12> c{};
            for (int i = 0; i < 12; ++i) {
                auto [a,b] = pat[i];
                c[i] = edge_var(n, sub[a], sub[b]);
            }
            clauses.push_back(c);
        }
    } while (prev_permutation(mask.begin(), mask.end()));
    int m = clauses.size();
    fprintf(stderr, "n=%d vars=%d cube clauses/color=%d total=%d\n", n, vars, m, 2*m);
    vector<vector<pair<int, unsigned char>>> occ(vars);
    for (int ci = 0; ci < m; ++ci) for (int v : clauses[ci]) occ[v].push_back({ci, 1});

    auto start = chrono::steady_clock::now();
    double limit = argc > 2 ? atof(argv[2]) : 600.0;
    vector<unsigned char> asg(vars), red_cnt(m);
    vector<int> red_full_occ(vars), blue_full_occ(vars), red_make_full(vars), blue_make_full(vars);
    vector<int> unsat, pos(2*m, -1);
    auto elapsed = [&] { return chrono::duration<double>(chrono::steady_clock::now() - start).count(); };
    auto add = [&](int id) {
        if (pos[id] < 0) { pos[id] = (int)unsat.size(); unsat.push_back(id); }
    };
    auto rem = [&](int id) {
        int p = pos[id];
        if (p >= 0) {
            int last = unsat.back();
            unsat[p] = last; pos[last] = p;
            unsat.pop_back(); pos[id] = -1;
        }
    };
    for (int attempt = 0; elapsed() < limit; ++attempt) {
        XorShift rng(0x123456789abcdefULL + attempt * 0x9e3779b97f4a7c15ULL);
        for (int v = 0; v < vars; ++v) asg[v] = rng.next() & 1;
        fill(red_cnt.begin(), red_cnt.end(), 0);
        fill(red_full_occ.begin(), red_full_occ.end(), 0);
        fill(blue_full_occ.begin(), blue_full_occ.end(), 0);
        fill(red_make_full.begin(), red_make_full.end(), 0);
        fill(blue_make_full.begin(), blue_make_full.end(), 0);
        fill(pos.begin(), pos.end(), -1);
        unsat.clear();
        auto add_contrib = [&](int ci) {
            int r = red_cnt[ci];
            if (r == 12) {
                for (int u : clauses[ci]) red_full_occ[u]++;
            } else if (r == 0) {
                for (int u : clauses[ci]) blue_full_occ[u]++;
            } else if (r == 11) {
                for (int u : clauses[ci]) if (!asg[u]) { red_make_full[u]++; break; }
            } else if (r == 1) {
                for (int u : clauses[ci]) if (asg[u]) { blue_make_full[u]++; break; }
            }
        };
        auto del_contrib = [&](int ci) {
            int r = red_cnt[ci];
            if (r == 12) {
                for (int u : clauses[ci]) red_full_occ[u]--;
            } else if (r == 0) {
                for (int u : clauses[ci]) blue_full_occ[u]--;
            } else if (r == 11) {
                for (int u : clauses[ci]) if (!asg[u]) { red_make_full[u]--; break; }
            } else if (r == 1) {
                for (int u : clauses[ci]) if (asg[u]) { blue_make_full[u]--; break; }
            }
        };
        for (int ci = 0; ci < m; ++ci) {
            int r = 0;
            for (int v : clauses[ci]) r += asg[v];
            red_cnt[ci] = r;
            if (r == 12) add(ci);
            if (r == 0) add(m + ci);
            add_contrib(ci);
        }
        uint64_t max_steps = 200000000ULL;
        for (uint64_t step = 0; step < max_steps && elapsed() < limit; ++step) {
            if (unsat.empty()) {
                printf("FOUND n=%d attempt=%d step=%llu\n", n, attempt, (unsigned long long)step);
                for (int v = 0; v < vars; ++v) printf("%d%c", (int)asg[v], v+1==vars?'\n':' ');
                return 0;
            }
            int uid = unsat[rng.randint((int)unsat.size())];
            int ci = uid % m;
            int best = clauses[ci][rng.randint(12)];
            int best_delta = 1<<29, ties = 0;
            bool noise = (rng.next() % 100) < 2;
            if (!noise) {
                for (int v : clauses[ci]) {
                    int delta = asg[v] ? (-red_full_occ[v] + blue_make_full[v])
                                       : (-blue_full_occ[v] + red_make_full[v]);
                    if (delta < best_delta || (delta == best_delta && rng.randint(++ties) == 0)) {
                        if (delta < best_delta) ties = 1;
                        best_delta = delta; best = v;
                    }
                }
            }
            int v = best;
            unsigned char old = asg[v];
            for (auto [cj, ign] : occ[v]) {
                int before_r = red_cnt[cj];
                if (before_r == 12) rem(cj);
                if (before_r == 0) rem(m+cj);
                del_contrib(cj);
                if (old) red_cnt[cj]--;
                else red_cnt[cj]++;
                int after_r = red_cnt[cj];
                if (after_r == 12) add(cj);
                if (after_r == 0) add(m+cj);
                asg[v] = old ^ 1;
                add_contrib(cj);
                asg[v] = old;
            }
            asg[v] = old ^ 1;
            if ((step & ((1<<20)-1)) == 0 && attempt == 0) fprintf(stderr, "t=%.1f step=%llu unsat=%zu best_delta=%d\n", elapsed(), (unsigned long long)step, unsat.size(), best_delta);
        }
        fprintf(stderr, "restart %d t=%.1f unsat=%zu\n", attempt, elapsed(), unsat.size());
    }
    fprintf(stderr, "not found\n");
    return 1;
}
