// TLE O(4^n n^2) #include #include #include #include #include #include #include constexpr size_t N_MAX = 13; namespace library { namespace bits { template , std::nullptr_t> = nullptr> T kth_bit(T v, size_t k) { return (v >> k) & 1; } template , std::nullptr_t> = nullptr> size_t bit_length(const T v) { if constexpr (std::numeric_limits>::digits <= 32) { return 32 - __builtin_clz(v); } else { return 64 - __builtin_clzll(v); } } template , std::nullptr_t> = nullptr> size_t popcount(const T v) { if constexpr (std::numeric_limits>::digits <= 32) { return __builtin_popcount(v); } else { return __builtin_popcountll(v); } } template , std::nullptr_t> = nullptr> size_t count_tz(const T v) { if constexpr (std::numeric_limits>::digits <= 32) { return __builtin_ctz(v); } else { return __builtin_ctzll(v); } } } namespace subset_transform { template void zeta(std::vector& x) { const size_t n = x.size(); for (size_t b = 1; b < n; b *= 2) for (size_t l = 0; l < n; l += 2 * b) for (size_t i = l; i < l + b; ++i) { x[i + 1 * b] += x[i + 0 * b]; } } template void mobius(std::vector& x) { const size_t n = x.size(); for (size_t b = 1; b < n; b *= 2) for (size_t l = 0; l < n; l += 2 * b) for (size_t i = l; i < l + b; ++i) { x[i + 1 * b] -= x[i + 0 * b]; } } } namespace set_power_series { namespace details { struct polynomial { polynomial() : polynomial(0) {} explicit polynomial(size_t n, uint64_t value = {}) { assign(n, value); } size_t size() const { return _size; } uint64_t& operator[](size_t i) { return _data[i]; } const uint64_t& operator[](size_t i) const { return _data[i]; } void assign(size_t n, uint64_t v) { _size = std::min(n, N_MAX + 1); std::fill(_data.begin(), _data.begin() + _size, v); } void resize(size_t n, uint64_t v) { size_t nxt_size = std::min(n, N_MAX + 1); if (nxt_size > _size) { std::fill(_data.begin() + _size, _data.begin() + nxt_size, v); _size = nxt_size; } } void push_front(uint64_t v) { uint64_t back = _data[_size - 1]; for (size_t i = _size; i --> 1;) { _data[i] = _data[i - 1]; } _data[0] = v; if (_size != N_MAX + 1) { _data[_size++] = back; } } polynomial& operator+=(const polynomial& q) { const size_t n = size(); for (size_t i = 0; i < q.size(); ++i) (*this)[i] += q[i]; return *this; } polynomial& operator-=(const polynomial& q) { const size_t n = this->size(); for (size_t i = 0; i < q.size(); ++i) (*this)[i] -= q[i]; return *this; } polynomial& operator*=(const polynomial& q) { const size_t n = size(), m = q.size(); resize(n + m - 1, 0); const size_t k = size(); for (size_t i = n; i --> 0;) { const uint64_t v = std::exchange((*this)[i], 0); const size_t jmax = std::min(k - i, m); for (size_t j = 0; j < jmax; ++j) { (*this)[i + j] += v * q[j]; } } return *this; } polynomial& muleq(const polynomial& q, size_t siz) { const size_t n = size(), m = q.size(); resize(std::min(siz, n + m - 1), 0); const size_t k = size(); for (size_t i = n; i --> 0;) { const uint64_t v = std::exchange((*this)[i], 0); const size_t jmax = std::min(k - i, m); for (size_t j = 0; j < jmax; ++j) { (*this)[i + j] += v * q[j]; } } return *this; } private: std::array _data; size_t _size; }; template std::vector add_rank(InputIterator first, InputIterator last) { const size_t n = last - first; std::vector fs(n); for (size_t i = 0; i < n; ++i) { size_t popc = bits::popcount(i); fs[i].assign(popc + 1, 0); fs[i][popc] = first[i]; } return fs; } std::vector add_rank(const std::vector &a) { return add_rank(a.begin(), a.end()); } std::vector remove_rank(const std::vector& polys) { const size_t n = polys.size(); std::vector a(n); for (size_t i = 0; i < n; ++i) a[i] = polys[i][bits::popcount(i)]; return a; } } std::vector subset_exp(const std::vector& f) { assert(f[0] == 0); const size_t n = bits::bit_length(f.size()) - 1; auto rf = details::add_rank({ 1 }); rf.reserve(size_t(1) << n); for (size_t i = 0; i < n; ++i) { auto rg = details::add_rank(f.begin() + (1 << i), f.begin() + (1 << (i + 1))); subset_transform::zeta(rg); for (size_t j = 0; j < size_t(1) << i; ++j) { rg[j].push_front(1); rg[j].muleq(rf[j], i + 2); rf.push_back(rg[j]); } } subset_transform::mobius(rf); return details::remove_rank(rf); } } } using vertex = size_t; using vertex_set = size_t; using edge = std::pair; using Int = uint64_t; using set_power_series = std::vector; std::vector count_cycles(const size_t n, const size_t, const std::vector& edges) { // adjacency list std::vector adj(n, std::vector{}); for (const auto& [u, v] : edges) adj[u].push_back(v), adj[v].push_back(u); // "c" mentioned in the editorial std::vector c(1u << n); // dp[S: vertex set][v: vertex] := # simple paths from min S to v passing vertices in S (but not passing vertices not in S) std::vector dp(1u << n, std::vector(n)); // base cases for (vertex v = 0; v < n; ++v) { dp[1u << v][v] = 1; } for (vertex_set S = 1; S < 1u << n; ++S) { // min S const vertex start = library::bits::count_tz(S); for (vertex cur = 0; cur < n; ++cur) for (const vertex nxt : adj[cur]) { if (start == nxt) { c[S] += dp[S][cur]; } else if (start < nxt and not library::bits::kth_bit(S, nxt)) { const vertex_set T = S | (1u << nxt); dp[T][nxt] += dp[S][cur]; } } } for (vertex_set S = 1; S < 1u << n; ++S) { const size_t card = library::bits::popcount(S); if (card == 1) c[S] = 1; if (card == 2) c[S] = 0; if (card >= 3) c[S] /= 2; } return c; } Int solve(const size_t n, const size_t m, const std::vector &edges) { // E[S: vertex set] := # edges connecting vertices in S. std::vector E(1u << n); for (const auto& [u, v] : edges) ++E[(1u << u) | (1u << v)]; library::subset_transform::zeta(E); // "c" mentioned in the editorial const set_power_series c = count_cycles(n, m, edges); // "f" mentioned in the editorial set_power_series f(1u << n); for (vertex_set C = 1; C < 1u << n; ++C) if (c[C]) { // max C const vertex t = library::bits::bit_length(C) - 1; // {0, ..., t} - C const vertex_set S = ((1u << (t + 1)) - 1) ^ C; // "g_C" mentioned in the editorial set_power_series g(1u << t); for (vertex_set T = S;; --T &= S) { g[T] = f[T] * (E[T | C] - E[T] - E[C]); if (T == 0) break; } // "h_C" mentioned in the editorial const set_power_series h = library::set_power_series::subset_exp(g); for (vertex_set T = S;; --T &= S) { f[C | T] += c[C] * h[T]; if (T == 0) break; } } return library::set_power_series::subset_exp(f).back(); } int main() { size_t n, m; std::cin >> n >> m; std::vector edges(m); for (auto &[u, v] : edges) { std::cin >> u >> v; --u, --v; } std::cout << solve(n, m, edges) << '\n'; }