結果
| 問題 |
No.2507 Yet Another Subgraph Counting
|
| コンテスト | |
| ユーザー |
hashiryo
|
| 提出日時 | 2023-10-30 19:10:43 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 59 ms / 2,000 ms |
| コード長 | 19,538 bytes |
| コンパイル時間 | 2,618 ms |
| コンパイル使用メモリ | 209,764 KB |
| 最終ジャッジ日時 | 2025-02-17 17:04:30 |
|
ジャッジサーバーID (参考情報) |
judge3 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 52 |
ソースコード
// #define _GLIBCXX_DEBUG
#include <bits/stdc++.h>
// clang-format off
std::ostream&operator<<(std::ostream&os,std::int8_t x){return os<<(int)x;}
std::ostream&operator<<(std::ostream&os,std::uint8_t x){return os<<(int)x;}
std::ostream&operator<<(std::ostream&os,const __int128_t &v){if(!v)os<<"0";__int128_t tmp=v<0?(os<<"-",-v):v;std::string s;while(tmp)s+='0'+(tmp%10),tmp/=10;return std::reverse(s.begin(),s.end()),os<<s;}
std::ostream&operator<<(std::ostream&os,const __uint128_t &v){if(!v)os<<"0";__uint128_t tmp=v;std::string s;while(tmp)s+='0'+(tmp%10),tmp/=10;return std::reverse(s.begin(),s.end()),os<<s;}
#define checkpoint() (void(0))
#define debug(...) (void(0))
#define debugArray(x,n) (void(0))
#define debugMatrix(x,h,w) (void(0))
// clang-format on
template <unsigned short MAX_N= 21> struct SetPowerSeries {
#define SUBSET_REP(i, j, n) \
for (int _= (n); _>>= 1;) \
for (int __= 0, _2= _ << 1; __ < (n); __+= _2) \
for (int j= __, i= j | _, ___= i; j < ___; ++j, ++i)
template <typename T> static inline void ranked_zeta_tr(const T f[], T ret[][MAX_N + 1], const int sz) {
for (int S= sz, c; S--;) ret[S][c= __builtin_popcount(S)]= f[S], std::fill_n(ret[S], c, 0);
SUBSET_REP(S, U, sz)
for (int d= __builtin_popcount(S); d--;) ret[S][d]+= ret[U][d];
}
template <typename T> static inline void conv_na(const T f[], const T g[], T ret[], const int sz) {
for (int s= sz, t; s--;)
for (ret[t= s]= f[s] * g[0]; t; --t&= s) ret[s]+= f[s ^ t] * g[t];
}
template <typename T> static inline void conv_tr(const T f[], const T g[], T ret[], const int sz) {
static T F[1 << MAX_N][MAX_N + 1], G[1 << MAX_N][MAX_N + 1];
T tmp[MAX_N + 1];
ranked_zeta_tr(f, F, sz), ranked_zeta_tr(g, G, sz);
const int n= __builtin_ctz(sz);
for (int S= sz, c, d, e, bg; S--;) {
c= __builtin_popcount(S), bg= std::min(2 * c, n);
for (d= bg; d >= c; d--)
for (tmp[d]= 0, e= d - c; e <= c; ++e) tmp[d]+= F[S][e] * G[S][d - e];
for (d= bg; d >= c; d--) F[S][d]= tmp[d];
}
SUBSET_REP(S, U, sz)
for (int c= __builtin_popcount(U), d= std::min(2 * c, n); d > c; d--) F[S][d]-= F[U][d];
for (int S= sz; S--;) ret[S]= F[S][__builtin_popcount(S)];
}
template <typename T, class F> static inline void onconv_na(const T g[], T ret[], const F &phi, const int sz) {
for (int s= 1, t; s < sz; phi(s, ret[s]), ++s)
for (ret[t= s]= 0; t; --t&= s) ret[s]+= ret[s ^ t] * g[t];
}
template <typename T, class F> static inline void onconv_tr(const T g[], T ret[], const F &phi, const int sz) {
static T G[1 << MAX_N][MAX_N + 1], mat[MAX_N + 1][1 << MAX_N];
const int n= __builtin_ctz(sz);
ranked_zeta_tr(g, G, sz), std::fill_n(mat[0], sz, ret[0]);
for (int d= n; d; d--) std::fill_n(mat[d], sz, 0);
for (int I= sz; I>>= 1;) phi(I, mat[1][I]= ret[0] * g[I]);
for (int d= 2; d <= n; ++d) {
SUBSET_REP(S, U, sz) mat[d - 1][S]+= mat[d - 1][U];
for (int S= sz; S--;)
if (int c= __builtin_popcount(S); c <= d && d <= 2 * c)
for (int e= d; e--;) mat[d][S]+= mat[e][S] * G[S][d - e];
SUBSET_REP(S, U, sz) mat[d][S]-= mat[d][U];
for (int S= sz; S--;) __builtin_popcount(S) == d ? phi(S, mat[d][S]), 0 : (mat[d][S]= 0);
}
for (int S= sz; --S;) ret[S]= mat[__builtin_popcount(S)][S];
}
public:
template <typename T> // O(n 2^n)
static inline void subset_sum(std::vector<T> &f) {
SUBSET_REP(S, U, f.size()) f[S]+= f[U];
}
template <typename T> // O(n 2^n)
static inline void subset_sum_inv(std::vector<T> &f) {
SUBSET_REP(S, U, f.size()) f[S]-= f[U];
}
template <class T> // O(n^2 2^n)
static inline std::vector<T> convolve(const std::vector<T> &f, const std::vector<T> &g) {
const int sz= f.size(), n= __builtin_ctz(sz);
std::vector<T> ret(sz);
if (n <= 10) return conv_na(f.data(), g.data(), ret.data(), sz), ret;
assert(sz == 1 << n && sz == g.size());
return conv_tr(f.data(), g.data(), ret.data(), sz), ret;
}
// f(S) = φ_S ( Σ_{T⊊S} f(T)g(S/T) )
template <class T, class F= void (*)(int, T &)> // O(n^2 2^n)
static inline std::vector<T> semi_relaxed_convolve(
const std::vector<T> &g, T init, const F &phi= [](int, T &) {}) {
const int sz= g.size(), n= __builtin_ctz(sz);
std::vector<T> ret(sz);
ret[0]= init;
if (n <= 12) return onconv_na(g.data(), ret.data(), phi, sz), ret;
assert(sz == 1 << n);
return onconv_tr(g.data(), ret.data(), phi, sz), ret;
}
// f(S) = φ_S ( Σ_{∅≠T⊊S & (T<(S/T) as binary numbers) } f(T)f(S/T) )
template <class T, class F> // O(n^2 2^n)
static inline std::vector<T> self_relaxed_convolve(int n, const F &phi) {
assert(__builtin_popcount(n) == 1);
int I= 1, ed= std::min(1 << 13, n);
std::vector<T> ret(n, 0);
for (int s, t, u= 1; I < ed; I<<= 1)
for (t= s= 0; s < I; phi(u, ret[u]), t= ++s, ++u)
for (ret[u]= 0; t; --t&= s) ret[u]+= ret[u ^ t] * ret[t];
T *h= ret.data();
for (; I < n; I<<= 1)
phi(I, ret[I]), onconv_tr(
h, h + I, [&](int s, T &x) { phi(s | I, x); }, I);
return ret;
}
// F(f) : F[i] is coefficient of EGF ( = F^{(i)}(0) )
// "f[∅] = 0" is required.
template <class T, class EGF> // O(n^2 2^n)
static inline std::vector<T> composite(const std::vector<T> &f, const EGF &F) {
const int sz= f.size(), m= __builtin_ctz(sz), sz2= sz >> 1;
assert(sz == 1 << m), assert(f.at(0) == 0);
std::vector<T> ret(sz);
T *h= ret.data() + sz;
const T *g= f.data();
for (int i= 0; i <= m; ++i) ret[sz - (1 << i)]= F[m - i];
int l= 1, ed= std::min(sz, 1 << 11), j;
for (; l < ed; l<<= 1)
for (j= sz2; j >= l; j>>= 1) conv_na(h - j, g + l, h - j - j + l, l);
for (; l < sz; l<<= 1)
for (j= sz2; j >= l; j>>= 1) conv_tr(h - j, g + l, h - j - j + l, l);
return ret;
}
// exp(f) : "f[∅] = 0" is required.
template <class T> // O(n^2 2^n)
static inline std::vector<T> exp(const std::vector<T> &f) {
const int sz= f.size();
assert(!(sz & (sz - 1))), assert(f.at(0) == 0);
T h[sz];
const T *g= f.data();
int l= 1, ed= std::min(sz, 1 << 11);
for (h[0]= 1; l < ed; l<<= 1) conv_na(h, g + l, h + l, l);
for (; l < sz; l<<= 1) conv_tr(h, g + l, h + l, l);
return std::vector<T>(h, h + sz);
}
// log(f) : "f[∅] = 1" is required.
template <class T> // O(n^2 2^n)
static inline std::vector<T> log(const std::vector<T> &f) {
const int sz= f.size();
assert(!(sz & (sz - 1))), assert(f.at(0) == T(1));
int I= 2, ed= std::min(sz, 1 << 13);
T h[sz];
const T *g= f.data();
for (std::copy_n(g, ed, h); I < ed; I<<= 1)
for (int s= 1, u= s | I; s < I; ++s, ++u)
for (int t= s; t; --t&= s) h[u]-= h[u ^ t] * f[t];
for (; I < sz; I<<= 1)
h[I]= g[I], onconv_tr(
g, h + I, [&](int s, T &x) { x= g[I | s] - x; }, I);
return h[0]= 0, std::vector<T>(h, h + sz);
}
// f^k
template <class T> // O(n^2 2^n)
static inline std::vector<T> pow(std::vector<T> f, uint64_t k) {
const int sz= f.size(), n= __builtin_ctz(sz);
assert(sz == 1 << n);
T F[MAX_N + 1]= {1}, pw= 1, bs= f[0];
int i= 1, ed= std::min<uint64_t>(n, k);
for (; i <= ed; ++i) F[i]= F[i - 1] * (k - i + 1);
for (auto e= k - --i; e; e>>= 1, bs*= bs)
if (e & 1) pw*= bs;
for (; i >= 0; --i, pw*= f[0]) F[i]*= pw;
return f[0]= 0, composite(f, F);
}
// P(f), P is polynomial
template <class T> static inline std::vector<T> polynomial_composite(std::vector<T> f, std::vector<T> P) {
const int sz= f.size(), n= __builtin_ctz(sz);
assert(sz == 1 << n);
T F[MAX_N + 1]= {};
int e= P.size();
if (!e) return std::vector<T>(sz);
for (int j= 0;; ++j, --e) {
for (int i= e; i--;) (F[j]*= f[0])+= P[i];
if (j == n || e == 1) break;
for (int i= 1; i < e; ++i) P[i - 1]= P[i] * i;
}
return f[0]= 0, composite(f, F);
}
// {[X^{[n]}]f^k/k!} for k=0,1,...,n
template <class T> // O(n^2 2^n)
static inline std::vector<T> egf(std::vector<T> f) {
static constexpr int M= 1 << 11;
const int sz= f.size(), n= __builtin_ctz(sz), sz4= sz >> 2;
assert(sz == 1 << n);
if (n == 1) return {0, f[1]};
int l= sz4, m;
T *in= f.data() + l, *dp= in + l, tmp[sz4 / 2], *dp2;
for (int s; l > M; conv_tr(dp, in, dp, l), in-= (l>>= 1))
for (m= sz4; dp2= dp + (m - l), m > l; m>>= 1)
for (s= l, conv_tr(dp2 + m - l, in, tmp, l); s--;) dp2[s]+= tmp[s];
for (int s; l; conv_na(dp, in, dp, l), in-= (l>>= 1))
for (m= sz4; dp2= dp + (m - l), m > l; m>>= 1)
for (s= l, conv_na(dp2 + m - l, in, tmp, l); s--;) dp2[s]+= tmp[s];
std::vector<T> ret(n + 1, 0);
for (int i= n + 1; --i;) ret[i]= dp[(1 << (n - i)) - 1];
return ret;
}
// {[X^{[n]}]g*f^k/k!} for k=0,1,...,n
template <class T> // O(n^2 2^n)
static inline std::vector<T> egf(const std::vector<T> &f, std::vector<T> g) {
static constexpr int M= 1 << 11;
const int sz= f.size(), n= __builtin_ctz(sz), sz2= sz >> 1, sz4= sz >> 2;
assert(sz == 1 << n), assert(sz == (int)g.size());
if (n == 1) return {g[1], f[1] * g[0] + f[0] * g[1]};
int l= sz2, m;
const T *in= f.data() + sz2;
T *dp= g.data(), tmp[sz2 / 2], *dp2;
for (int s; l > M; conv_tr(dp, in, dp, l), in-= (l>>= 1))
for (m= sz2; dp2= dp + (m - l), m > l; m>>= 1)
for (s= l, conv_tr(dp2 + m - l, in, tmp, l); s--;) dp2[s]+= tmp[s];
for (int s; l; conv_na(dp, in, dp, l), in-= (l>>= 1))
for (m= sz2; dp2= dp + (m - l), m > l; m>>= 1)
for (s= l, conv_na(dp2 + m - l, in, tmp, l); s--;) dp2[s]+= tmp[s];
std::vector<T> ret(n + 1);
for (int i= n + 1; i--;) ret[i]= dp[(1 << (n - i)) - 1];
return ret;
}
#undef SUBSET_REP
};
template <unsigned short MAX_V= 21> class UndirectedGraphSetPowerSeries {
using SPS= SetPowerSeries<MAX_V>;
template <class T> using sps= std::vector<T>;
template <class T> using poly= std::vector<T>;
const unsigned V, sz;
unsigned adj[MAX_V][MAX_V]= {0}, edge[MAX_V]= {0};
template <class T> static inline T pow(T x, int k) {
for (T ret(1);; x*= x)
if (k & 1 ? ret*= x : 0; !(k>>= 1)) return ret;
}
template <class F> inline void bfs(int s, const F &f) const {
for (int t= s, u, j; t;)
for (f(u= 1 << __builtin_ctz(t)); u;) j= __builtin_ctz(u), t^= 1 << j, u^= 1 << j, u|= edge[j] & t;
}
public:
UndirectedGraphSetPowerSeries(int n): V(n), sz(1 << V) {}
UndirectedGraphSetPowerSeries(const std::vector<std::vector<int>> &g): V(g.size()), sz(1 << V) {
for (int i= V; i--;)
for (int j= i; j--;) assert(g[i][j] == g[j][i]);
for (int i= V; i--;)
for (int j= V; j--;) adj[i][j]= g[i][j];
for (int i= V; i--;)
for (int j= V; j--;) edge[i]|= !(!(adj[i][j])) << j;
}
int *operator[](int u) const { return adj[u]; }
void add_edge(int u, int v, int cnt= 1) {
adj[u][v]= (adj[v][u]+= cnt), edge[u]|= (1 << v), edge[v]|= (1 << u);
if (!(adj[u][v])) edge[u]^= (1 << v), edge[v]^= (1 << u);
}
template <class T> static inline sps<T> space_size(const sps<int> &rank) {
sps<T> ret(rank.size());
for (int s= rank.size(); s--;) ret[s]= pow<T>(2, rank[s]);
return ret;
}
template <class T, class G> static inline void transform(sps<T> &f, const G &g) {
const int sz2= f.size() / 2;
sps<T> tmp(sz2);
for (int I= sz2; I; I>>= 1) {
for (int t= 0; t < sz2; t+= I)
for (int u= I, t2= t << 1; u--;) tmp[t | u]= f[t2 | I | u];
tmp= g(tmp);
for (int t= 0; t < sz2; t+= I)
for (int u= I, t2= t << 1; u--;) f[t2 | I | u]= tmp[t | u];
}
}
template <class T> // O(V^3 2^V)
static inline void connect_to_biconnect(sps<T> &f) {
transform(f, SPS::template log<T>);
}
template <class T> // O(V^3 2^V)
static inline void biconnect_to_connect(sps<T> &f) {
transform(f, SPS::template exp<T>);
}
template <class T> // O(V 2^V)
inline void loop_ignored_to_loop_permitted(sps<T> &f) const {
auto tmp= space_size<T>(loop_size());
for (int s= sz; s--;) f[s]*= tmp[s];
}
inline sps<int> edge_space_rank() const { // O(V 2^V)
sps<int> ret(sz, 0);
for (int i= V; i--;)
for (int j= i + 1; j--;) ret[(1 << i) | (1 << j)]= adj[i][j];
return SPS::subset_sum(ret), ret;
}
inline sps<int> loop_size() const { // O(V 2^V)
sps<int> ret(sz, 0);
for (int i= V; i--;) ret[(1 << i)]= adj[i][i];
return SPS::subset_sum(ret), ret;
}
inline sps<int> loop_ignored_edge_space_rank() const { // O(V 2^V)
sps<int> ret(sz, 0);
for (int i= V; i--;)
for (int j= i; j--;) ret[(1 << i) | (1 << j)]= adj[i][j];
return SPS::subset_sum(ret), ret;
}
inline sps<int> connected_component_num() const { // O(V 2^V)
sps<int> ret(sz, 0);
for (int s= sz; s--;) bfs(s, [&](int) { ret[s]++; });
return ret;
}
inline sps<int> cycle_space_rank() const { // O(V 2^V)
sps<int> e= edge_space_rank(), k= connected_component_num(), ret(sz, 0);
for (int s= sz; s--;) ret[s]= e[s] + k[s] - __builtin_popcount(s);
return ret;
}
template <class T> // O(V 2^V)
inline sps<T> edge_space_size() const {
return space_size<T>(edge_space_rank());
}
template <class T> // O(V 2^V)
inline sps<T> loop_ignored_edge_space_size() const {
return space_size<T>(loop_ignored_edge_space_rank());
}
template <class T> // O(V 2^V)
inline sps<T> cycle_space_size() const {
return space_size<T>(cycle_space_rank());
}
template <class T> // O(V^2 2^V)
inline sps<T> connected_graph_num() const {
return SPS::log(edge_space_size<T>());
}
template <class T> // O(V^2 2^V)
inline sps<T> loop_ignored_connected_graph_num() const {
return SPS::log(loop_ignored_edge_space_size<T>());
}
template <class T> // O(V^2 2^V)
inline sps<T> euler_graph_num() const {
return SPS::log(cycle_space_size<T>());
}
template <class T> // O(V^2 2^V)
inline sps<T> connected_biparate_graph_num() const {
sps<T> tmp= edge_space_size<T>(), ret(sz, 1);
for (int s= sz; s--;) ret[s]/= tmp[s];
ret= SPS::convolve(ret, ret);
for (int s= sz; s--;) ret[s]*= tmp[s];
ret= SPS::log(ret);
for (int s= sz; s--;) ret[s]/= 2;
return ret;
}
template <class T> // O(V^3 2^V)
inline sps<T> loop_ignored_biconnected_graph_num() const {
auto ret= loop_ignored_connected_graph_num<T>();
return connect_to_biconnect(ret), ret;
}
template <class T> // O(V^3 2^V)
inline sps<T> biconnected_graph_num() const {
auto ret= loop_ignored_biconnected_graph_num<T>();
return loop_ignored_to_loop_permitted(ret), ret;
}
template <class T> // O(V^2 2^V)
inline sps<T> spanning_tree_num() const {
sps<int> e= edge_space_rank();
sps<T> ret= {0, 1};
ret.reserve(sz);
for (int I= 2; I < sz; I<<= 1) {
sps<T> g(ret);
for (int s= I; --s;) g[s]*= e[s | I] - e[s] - e[I];
g= SPS::exp(g);
std::copy(g.begin(), g.end(), std::back_inserter(ret));
}
return ret;
}
template <class T> // O(V^2 2^V)
inline sps<T> forest_num() const {
return SPS::exp(spanning_tree_num<T>());
}
template <class T> // O(V^2 2^V)
inline sps<T> rooted_spanning_tree_num() const {
auto ret= spanning_tree_num<T>();
for (int s= sz; s--;) ret[s]*= __builtin_popcount(s);
return ret;
}
template <class T> // O(V^2 2^V)
inline sps<T> rooted_forest_num() const {
return SPS::exp(rooted_spanning_tree_num<T>());
}
template <class T> // O(V^2 2^V)
inline sps<T> cycle_graph_num() const {
T dp[sz][V - 1];
sps<T> ret(sz, 0);
for (int i= V, I= sz; I>>= 1, --i;) {
for (int s= I; --s;) std::fill_n(dp[s], i, 0);
for (int j= i; j--;) dp[1 << j][j]= adj[i][j];
for (int s= 1; s < I; s++)
for (int t= s, j, u, r, k; t; ret[s | I]+= dp[s][j] * adj[j][i])
for (t^= 1 << (j= __builtin_ctz(t)), u= r= s ^ (1 << j); u; dp[s][j]+= dp[r][k] * adj[k][j]) u^= 1 << (k= __builtin_ctz(u));
}
for (int i= V; i--;)
for (int j= i; j--;) ret[(1 << i) | (1 << j)]-= adj[i][j];
for (int s= sz; --s;) ret[s]/= 2;
for (int i= V; i--;) ret[1 << i]= adj[i][i];
return ret;
}
template <class T> // O(V^3 2^V)
inline sps<T> cactus_graph_num() const {
auto ret= cycle_graph_num<T>();
for (int i= V; i--;)
for (int j= i; j--;) ret[(1 << i) | (1 << j)]+= adj[i][j];
for (int i= V; i--;) ret[1 << i]= 0;
return biconnect_to_connect(ret), loop_ignored_to_loop_permitted(ret), ret;
}
template <class T> // O(V^3 2^V)
inline sps<T> two_edge_connected_graph_num() const {
const int sz2= sz / 2;
sps<T> ret= connected_graph_num<T>(), tmp(sz2), tmp2;
for (int i= V, I= sz2; --i; I>>= 1) {
for (int t= 0; t < sz2; t+= I)
for (int u= I, t2= t << 1; u--;) tmp[t | u]= ret[t2 | I | u];
tmp2.assign(sz2, 0);
for (int t= 0; t < sz2; t+= I)
for (int j= i, J= I, t2= t << 1; J>>= 1, j--;)
for (int s= J, J2= J * 2; s < I; s+= J2)
for (int u= s + J; u-- > s;) tmp2[t | u]-= ret[t2 | u] * adj[i][j];
tmp= SPS::convolve(tmp, SPS::exp(tmp2));
for (int t= 0; t < sz2; t+= I)
for (int u= I, t2= t << 1; u--;) ret[t2 | I | u]= tmp[t | u];
}
return ret;
}
template <class T> // O(V^3 2^V)
inline void transform_connect_by_bridge(sps<T> &f) const {
const int sz2= sz / 2;
sps<T> tmp(sz2), tmp2;
for (int i= V, I= sz2; --i; I>>= 1) {
for (int t= 0; t < sz2; t+= I)
for (int u= I, t2= t << 1; u--;) tmp[t | u]= f[t2 | I | u];
tmp2.assign(sz2, 0);
for (int t= 0; t < sz2; t+= I)
for (int j= i, J= I, t2= t << 1; J>>= 1, j--;)
for (int s= J, J2= J * 2; s < I; s+= J2)
for (int u= s + J; u-- > s;) tmp2[t | u]+= f[t2 | u] * adj[i][j];
tmp= SPS::convolve(tmp, SPS::exp(tmp2));
for (int t= 0; t < sz2; t+= I)
for (int u= I, t2= t << 1; u--;) f[t2 | I | u]= tmp[t | u];
}
}
template <class T> // O(V^2 2^V)
inline sps<T> acyclic_orientations() const {
auto k= connected_component_num();
sps<T> g(sz, 0);
for (int s= sz; --s;)
if (k[s] == __builtin_popcount(s)) g[s]= (k[s] + 1) & 1 ? -1 : 1;
return SPS::template semi_relaxed_convolve<T>(g, 1);
}
template <class T> // O(V^2 2^V)
inline std::vector<T> colorings_using_exactly_k_colors_num() const {
if (V == 0) return {0}; // impossible in any number of ways
for (int i= V; i--;)
if (adj[i][i]) return {0}; // impossible in any number of ways
auto k= connected_component_num();
std::vector<T> indep(sz, 0);
for (int s= sz; --s;) indep[s]= k[s] == __builtin_popcount(s);
return SPS::egf(indep);
}
template <class T> // O(V^2 2^V)
inline poly<T> chromatic_polynomial() const {
auto e= colorings_using_exactly_k_colors_num<T>();
if (e.back() == 0) return {0};
poly<T> ret(V + 1, 0);
T tmp[V]= {1};
for (int i= 1, j; i < V; i++)
for (j= i; j--; tmp[j]*= -i) ret[j + 1]+= tmp[j] * e[i], tmp[j + 1]+= tmp[j];
for (int j= V; j--;) ret[j + 1]+= tmp[j];
return ret;
}
template <class T> // O(V^2 2^V)
inline T tutte_polynomial(T x, T y) const {
int sum[sz], s, t, lim= 2, i, j;
T fum[10'000]= {0, 1};
std::vector<T> g= {0}, h;
for (g.reserve(sz), h.reserve(sz), i= 0; i < V; i++) {
for (sum[0]= j= 0; j < i; j++)
for (s= t= 1 << j; s--;) sum[s | t]= sum[s] + adj[i][j];
for (h.resize(s= 1 << i); s--; h[s]= g[s] * fum[sum[s]])
for (; lim <= sum[s]; lim++) fum[lim]= fum[lim - 1] * y + 1;
h= SPS::exp(h), std::copy(h.begin(), h.end(), std::back_inserter(g));
}
for (x-= 1, t= ~0, j= 0, i= V; i--;) j+= adj[i][i];
for (bfs((s= sz) - 1, [&](int u) { t^= u; }); --s&= t;) g[s]*= x;
return SPS::exp(g)[sz - 1] * pow(y, j);
}
};
using namespace std;
signed main() {
cin.tie(0);
ios::sync_with_stdio(0);
using GSPS= UndirectedGraphSetPowerSeries<15>;
using SPS= SetPowerSeries<15>;
int n, m;
cin >> n >> m;
GSPS g(n);
for (int i= 0; i < m; ++i) {
int u, v;
cin >> u >> v, --u, --v;
g.add_edge(u, v);
}
auto f= g.cycle_graph_num<long long>();
for (int i= n; i--;) f[1 << i]= 1;
g.transform_connect_by_bridge(f);
f= SetPowerSeries<>::exp(f);
cout << f.back() << '\n';
return 0;
}
hashiryo