#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <limits>
#include <string>
#include <unordered_map>
#include <vector>

using namespace std;

struct Scanner {
    static constexpr size_t BUFSZ = 1 << 20;
    FILE* f = nullptr;
    vector<char> buf;
    size_t pos = 0, len = 0;
    explicit Scanner(const char* path) : f(fopen(path, "rb")), buf(BUFSZ) {}
    ~Scanner() { if (f) fclose(f); }
    int get() {
        if (pos >= len) {
            len = f ? fread(buf.data(), 1, BUFSZ, f) : 0;
            pos = 0;
            if (!len) return EOF;
        }
        return (unsigned char)buf[pos++];
    }
    void skip_line() {
        int c;
        while ((c = get()) != EOF && c != '\n') {}
    }
    int next_non_ws() {
        while (true) {
            int c = get();
            if (c == EOF) return EOF;
            if (isspace(c)) continue;
            if (c == 'c') {
                skip_line();
                continue;
            }
            return c;
        }
    }
    bool read_word_raw(string& out) {
        out.clear();
        int c;
        do {
            c = get();
            if (c == EOF) return false;
        } while (isspace(c));
        while (c != EOF && !isspace(c)) {
            out.push_back((char)c);
            c = get();
        }
        return true;
    }
    bool read_int(int& out) {
        int c = next_non_ws();
        if (c == EOF) return false;
        int sign = 1;
        if (c == '-') {
            sign = -1;
            c = get();
        }
        int x = 0;
        while (c != EOF && isdigit(c)) {
            x = x * 10 + (c - '0');
            c = get();
        }
        out = sign * x;
        return true;
    }
    bool read_header(int& n, int& m) {
        int c;
        while ((c = next_non_ws()) != EOF) {
            if (c != 'p') {
                skip_line();
                continue;
            }
            string fmt;
            if (!read_word_raw(fmt)) return false;
            return fmt == "cnf" && read_int(n) && read_int(m);
        }
        return false;
    }
};

static int digits(int x) {
    int d = 1;
    while (x >= 10) {
        x /= 10;
        d++;
    }
    return d;
}

struct ResidualClause {
    vector<int> lits;
};

static bool dfs_hit(const vector<ResidualClause>& clauses, unordered_map<int, signed char>& assign,
                    int depth, long long& nodes, long long node_limit) {
    if (++nodes > node_limit) return true; // inconclusive: do not count as forced.
    int best = -1;
    size_t best_size = numeric_limits<size_t>::max();
    for (int i = 0; i < (int)clauses.size(); ++i) {
        bool sat = false;
        size_t open = 0;
        for (int lit : clauses[(size_t)i].lits) {
            auto it = assign.find(abs(lit));
            signed char want = lit > 0 ? 1 : -1;
            if (it != assign.end()) {
                if (it->second == want) {
                    sat = true;
                    break;
                }
            } else {
                open++;
            }
        }
        if (sat) continue;
        if (open == 0) return false;
        if (open < best_size) {
            best_size = open;
            best = i;
            if (open == 1) break;
        }
    }
    if (best < 0) return true;
    for (int lit : clauses[(size_t)best].lits) {
        int v = abs(lit);
        signed char want = lit > 0 ? 1 : -1;
        auto it = assign.find(v);
        if (it != assign.end()) {
            if (it->second == want && dfs_hit(clauses, assign, depth + 1, nodes, node_limit)) return true;
            continue;
        }
        assign.emplace(v, want);
        if (dfs_hit(clauses, assign, depth + 1, nodes, node_limit)) return true;
        assign.erase(v);
    }
    return false;
}

static bool group_forces_output(const vector<vector<int>>& group, int v, long long node_limit, bool& inconclusive) {
    vector<ResidualClause> residual;
    residual.reserve(group.size());
    for (const auto& c : group) {
        ResidualClause r;
        for (int lit : c) {
            if (abs(lit) != v) r.lits.push_back(lit);
        }
        sort(r.lits.begin(), r.lits.end(), [](int a, int b) {
            return abs(a) == abs(b) ? a < b : abs(a) < abs(b);
        });
        r.lits.erase(unique(r.lits.begin(), r.lits.end()), r.lits.end());
        bool taut = false;
        for (size_t i = 1; i < r.lits.size(); ++i) {
            if (abs(r.lits[i]) == abs(r.lits[i - 1]) && r.lits[i] == -r.lits[i - 1]) {
                taut = true;
                break;
            }
        }
        if (!taut) residual.push_back(std::move(r));
    }
    unordered_map<int, signed char> assign;
    assign.reserve(32);
    long long nodes = 0;
    bool possible = dfs_hit(residual, assign, 0, nodes, node_limit);
    inconclusive = nodes > node_limit;
    return !possible && !inconclusive;
}

int main(int argc, char** argv) {
    if (argc != 2) {
        cerr << "usage: implicant_lower_bound formula.cnf\n";
        return 2;
    }
    int n = 0, m = 0;
    Scanner sc(argv[1]);
    if (!sc.f || !sc.read_header(n, m)) return 2;
    vector<vector<vector<int>>> groups((size_t)n + 1);
    vector<int> clause;
    clause.reserve(16);
    int lit;
    while (sc.read_int(lit)) {
        if (lit == 0) {
            int maxv = 0;
            for (int l : clause) maxv = max(maxv, abs(l));
            if (maxv > 0) groups[(size_t)maxv].push_back(clause);
            clause.clear();
        } else {
            clause.push_back(lit);
        }
    }
    long long forced = 0, defined = 0, inconclusive = 0, possible = 0;
    long long byte_lb = 15 + 4; // SAT line plus final v 0 line, rough minimum.
    const long long node_limit = 100000;
    for (int v = 1; v <= n; ++v) {
        if (groups[(size_t)v].empty()) continue;
        defined++;
        bool inc = false;
        if (group_forces_output(groups[(size_t)v], v, node_limit, inc)) {
            forced++;
            byte_lb += 1 + digits(v) + 1; // space, digits, and a worst-case sign.
        } else if (inc) {
            inconclusive++;
        } else {
            possible++;
        }
    }
    cout << "vars " << n << " clauses " << m << " defined_groups " << defined << "\n";
    cout << "forced_output_groups " << forced << " possible_without_output " << possible
         << " inconclusive " << inconclusive << "\n";
    cout << "signed_literal_byte_lower_bound " << byte_lb << "\n";
    return 0;
}
