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

using namespace std;

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;
}

struct Clause {
    vector<int> lits;
    bool learnt = false;
};

struct CDCL {
    int nvars;
    vector<Clause> clauses;
    vector<vector<int>> watches;
    vector<signed char> val;
    vector<unsigned char> phase;
    vector<int> lev, reason, trail, trail_lim;
    vector<double> activity;
    vector<unsigned char> seen;
    int qhead = 0;
    uint64_t conflicts = 0, decisions = 0;
    double var_inc = 1.0;
    chrono::steady_clock::time_point start = chrono::steady_clock::now();
    double limit = 600.0;

    explicit CDCL(int n) : nvars(n), watches(2*n), val(n, -1), phase(n, 1), lev(n, 0), reason(n, -1), activity(n, 0.0), seen(n, 0) {}
    static int mk_lit(int v, bool neg=false) { return 2*v + (neg ? 1 : 0); }
    static int var(int lit) { return lit >> 1; }
    static int neg(int lit) { return lit ^ 1; }
    int cur_level() const { return (int)trail_lim.size(); }
    bool lit_true(int lit) const {
        int v = var(lit);
        if (val[v] < 0) return false;
        bool want = (lit & 1) == 0;
        return (val[v] != 0) == want;
    }
    bool lit_false(int lit) const {
        int v = var(lit);
        if (val[v] < 0) return false;
        bool want = (lit & 1) == 0;
        return (val[v] != 0) != want;
    }
    bool enqueue(int lit, int why) {
        int v = var(lit);
        signed char want = (lit & 1) ? 0 : 1;
        if (val[v] != -1) return val[v] == want;
        val[v] = want;
        phase[v] = want;
        lev[v] = cur_level();
        reason[v] = why;
        trail.push_back(lit);
        return true;
    }
    int add_clause(vector<int> lits, bool learnt=false) {
        sort(lits.begin(), lits.end());
        lits.erase(unique(lits.begin(), lits.end()), lits.end());
        for (int lit : lits) {
            if (binary_search(lits.begin(), lits.end(), neg(lit))) return -2;
        }
        return attach_clause(std::move(lits), learnt);
    }
    int add_learnt_clause(vector<int> lits) {
        if (lits.empty()) return attach_clause(std::move(lits), true);
        int asserting = lits[0];
        vector<int> out;
        out.reserve(lits.size());
        out.push_back(asserting);
        bool taut = false;
        for (int i = 1; i < (int)lits.size(); ++i) {
            int lit = lits[i];
            if (lit == asserting) continue;
            if (lit == neg(asserting)) { taut = true; break; }
            bool dup = false;
            for (int x : out) {
                if (x == lit) { dup = true; break; }
                if (x == neg(lit)) { taut = true; break; }
            }
            if (taut) break;
            if (!dup) out.push_back(lit);
        }
        if (taut) return -2;
        if (out.size() > 2) {
            int best_i = 1, best_l = -1;
            for (int i = 1; i < (int)out.size(); ++i) {
                int l = lev[var(out[i])];
                if (l > best_l) { best_l = l; best_i = i; }
            }
            swap(out[1], out[best_i]);
        }
        return attach_clause(std::move(out), true);
    }
    int attach_clause(vector<int> lits, bool learnt) {
        int id = (int)clauses.size();
        clauses.push_back({std::move(lits), learnt});
        auto &c = clauses.back();
        if (c.lits.empty()) return id;
        if (c.lits.size() == 1) {
            watches[c.lits[0]].push_back(id);
        } else {
            watches[c.lits[0]].push_back(id);
            watches[c.lits[1]].push_back(id);
        }
        return id;
    }
    int propagate() {
        while (qhead < (int)trail.size()) {
            int p = trail[qhead++];
            int false_lit = neg(p);
            auto &ws = watches[false_lit];
            int i = 0, j = 0;
            while (i < (int)ws.size()) {
                int cid = ws[i++];
                Clause &c = clauses[cid];
                if (c.lits.size() == 1) {
                    ws[j++] = cid;
                    if (lit_false(c.lits[0])) {
                        while (i < (int)ws.size()) ws[j++] = ws[i++];
                        ws.resize(j);
                        return cid;
                    }
                    continue;
                }
                if (c.lits[0] != false_lit && c.lits[1] == false_lit) swap(c.lits[0], c.lits[1]);
                if (c.lits[0] != false_lit) {
                    ws[j++] = cid;
                    continue;
                }
                int other = c.lits[1];
                if (lit_true(other)) {
                    ws[j++] = cid;
                    continue;
                }
                bool moved = false;
                for (int k = 2; k < (int)c.lits.size(); ++k) {
                    int lit = c.lits[k];
                    if (!lit_false(lit)) {
                        c.lits[0] = lit;
                        c.lits[k] = false_lit;
                        watches[lit].push_back(cid);
                        moved = true;
                        break;
                    }
                }
                if (moved) continue;
                ws[j++] = cid;
                if (lit_false(other) || !enqueue(other, cid)) {
                    while (i < (int)ws.size()) ws[j++] = ws[i++];
                    ws.resize(j);
                    return cid;
                }
            }
            ws.resize(j);
        }
        return -1;
    }
    void new_decision_level() { trail_lim.push_back((int)trail.size()); }
    void backtrack(int lvl) {
        if (cur_level() <= lvl) return;
        int lim = lvl == 0 ? 0 : trail_lim[lvl];
        for (int i = (int)trail.size() - 1; i >= lim; --i) {
            int v = var(trail[i]);
            val[v] = -1;
            reason[v] = -1;
            lev[v] = 0;
        }
        trail.resize(lim);
        trail_lim.resize(lvl);
        qhead = min(qhead, (int)trail.size());
    }
    void bump_var(int v) {
        activity[v] += var_inc;
        if (activity[v] > 1e100) {
            for (double &a : activity) a *= 1e-100;
            var_inc *= 1e-100;
        }
    }
    int analyze(int confl, vector<int> &out, int &bt) {
        out.clear();
        out.push_back(-1);
        int path = 0;
        int p = -1;
        int idx = (int)trail.size() - 1;
        int cid = confl;
        vector<int> touched;
        do {
            Clause &c = clauses[cid];
            int skip = p >= 0 ? var(p) : -1;
            for (int lit : c.lits) {
                int v = var(lit);
                if (v == skip) continue;
                if (!seen[v] && lev[v] > 0) {
                    seen[v] = 1;
                    touched.push_back(v);
                    bump_var(v);
                    if (lev[v] == cur_level()) path++;
                    else out.push_back(lit);
                }
            }
            do {
                if (idx < 0) {
                    for (int v : touched) seen[v] = 0;
                    out.clear();
                    bt = 0;
                    return -1;
                }
                p = trail[idx--];
            } while (!seen[var(p)]);
            seen[var(p)] = 0;
            path--;
            cid = reason[var(p)];
        } while (path > 0 && cid >= 0);
        out[0] = neg(p);
        bt = 0;
        for (int i = 1; i < (int)out.size(); ++i) bt = max(bt, lev[var(out[i])]);
        for (int v : touched) seen[v] = 0;
        return 0;
    }
    int pick_branch() {
        int best = -1;
        double ba = -1;
        for (int v = 0; v < nvars; ++v) if (val[v] == -1 && activity[v] > ba) {
            ba = activity[v];
            best = v;
        }
        return best;
    }
    bool solve() {
        int confl = propagate();
        if (confl >= 0) return false;
        int restart_base = 100;
        while (true) {
            if (chrono::duration<double>(chrono::steady_clock::now() - start).count() > limit) {
                fprintf(stderr, "timeout conflicts=%llu decisions=%llu clauses=%zu level=%d\n",
                        (unsigned long long)conflicts, (unsigned long long)decisions, clauses.size(), cur_level());
                return true; // unknown/sat placeholder
            }
            confl = propagate();
            if (confl >= 0) {
                conflicts++;
                if (cur_level() == 0) {
                    fprintf(stderr, "UNSAT conflicts=%llu decisions=%llu clauses=%zu\n",
                            (unsigned long long)conflicts, (unsigned long long)decisions, clauses.size());
                    return false;
                }
                vector<int> learnt;
                int bt = 0;
                analyze(confl, learnt, bt);
                var_inc *= 1.05;
                backtrack(bt);
                if (learnt.empty()) {
                    fprintf(stderr, "empty learnt above root\n");
                    return false;
                }
                int id = add_learnt_clause(learnt);
                if (id >= 0 && !learnt.empty()) {
                    enqueue(learnt[0], id);
                }
                if ((conflicts % 1000) == 0) {
                    fprintf(stderr, "conf=%llu dec=%llu lvl=%d learnt=%zu len=%zu bt=%d\n",
                            (unsigned long long)conflicts, (unsigned long long)decisions, cur_level(),
                            clauses.size(), learnt.size(), bt);
                }
                if ((int)conflicts % restart_base == 0) backtrack(0);
            } else {
                int v = pick_branch();
                if (v < 0) {
                    fprintf(stderr, "SAT decisions=%llu conflicts=%llu\n", (unsigned long long)decisions, (unsigned long long)conflicts);
                    return true;
                }
                decisions++;
                new_decision_level();
                enqueue(mk_lit(v, phase[v] == 0), -1);
            }
        }
    }
};

int main(int argc, char **argv) {
    int n = argc > 1 ? atoi(argv[1]) : 13;
    double limit = argc > 2 ? atof(argv[2]) : 600.0;
    int vars = n * (n - 1) / 2;
    CDCL s(vars);
    s.limit = limit;
    auto pats = cube_patterns();
    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) {
            vector<int> pos, neg;
            pos.reserve(12);
            neg.reserve(12);
            for (auto [a,b] : pat) {
                int v = edge_var(n, sub[a], sub[b]);
                pos.push_back(CDCL::mk_lit(v, false));
                neg.push_back(CDCL::mk_lit(v, true));
                s.activity[v] += 1.0;
            }
            s.add_clause(pos, false);
            s.add_clause(neg, false);
        }
    } while (prev_permutation(mask.begin(), mask.end()));
    fprintf(stderr, "generated n=%d vars=%d clauses=%zu\n", n, vars, s.clauses.size());
    bool sat_or_unknown = s.solve();
    return sat_or_unknown ? 1 : 0;
}
