#include <iostream>using namespace std;using LL = long long;constexpr int MOD = int(1e9) + 7;// <<= '2. Number Theory .,//{namespace NT {void INC(int& a, int b) { a += b; if (a >= MOD) a -= MOD;}int sum(int a, int b) { a += b; if (a >= MOD) a -= MOD; return a;}void DEC(int& a, int b) { a -= b; if (a < 0) a += MOD;}int dff(int a, int b) { a -= b; if (a < 0) a += MOD; return a;}void MUL(int& a, int b) { a = (LL)a * b % MOD; }int pdt(int a, int b) { return (LL)a * b % MOD; }int _I(int b) { int a = MOD, x1 = 0, x2 = 1, q; while (1) { q = a / b, a %= b; if (!a) return x2; DEC(x1, pdt(q, x2)); q = b / a, b %= a; if (!b) return x1; DEC(x2, pdt(q, x1)); }}void DIV(int& a, int b) { MUL(a, _I(b)); }int qtt(int a, int b) { return pdt(a, _I(b)); }int pow(int a, LL b) { int c(1); while (b) { if (b & 1) MUL(c, a); MUL(a, a), b >>= 1; } return c;}template <class T>T pow(T a, LL b) { T c(1); while (b) { if (b & 1) c *= a; a *= a, b >>= 1; } return c;}template <class T>T pow(T a, int b) { return pow(a, (LL)b);}struct Int { int val; operator int() const { return val; } Int(int _val = 0) : val(_val) { val %= MOD; if (val < 0) val += MOD; } Int(LL _val) : val(_val) { _val %= MOD; if (_val < 0) _val += MOD; val = _val; } Int& operator+=(const int& rhs) { INC(val, rhs); return *this; } Int operator+(const int& rhs) const { return sum(val, rhs); } Int& operator-=(const int& rhs) { DEC(val, rhs); return *this; } Int operator-(const int& rhs) const { return dff(val, rhs); } Int& operator*=(const int& rhs) { MUL(val, rhs); return *this; } Int operator*(const int& rhs) const { return pdt(val, rhs); } Int& operator/=(const int& rhs) { DIV(val, rhs); return *this; } Int operator/(const int& rhs) const { return qtt(val, rhs); } Int operator-() const { return MOD - *this; }};} // namespace NTusing namespace NT;constexpr int N = int(1e3) + 9;Int binom[N][N], C[N], E[N], B[N], B1[N], G[N];int n;void ln(Int C[], Int G[]) { for (int i = 1; i <= n; ++i) { C[i] = G[i]; for (int j = 1; j <= i - 1; ++j) C[i] -= binom[i - 1][j - 1] * C[j] * G[i - j]; }}void exp(Int G[], Int C[]) { for (int i = 1; i <= n; ++i) { G[i] = C[i]; for (int j = 1; j <= i - 1; ++j) G[i] += binom[i - 1][j - 1] * C[j] * G[i - j]; }}int main() { cin.tie(nullptr)->sync_with_stdio(false); n = 1000; for (int i = 0; i < n + 1; ++i) { binom[i][0] = 1; for (int j = 0; j < i; ++j) binom[i][j + 1] = binom[i - 1][j] + binom[i - 1][j + 1]; } for (int i = 1; i <= n; ++i) G[i] = pow(2, binom[i][2]); ln(C, G); for (int i = 1; i <= n; ++i) G[i] = pow(2, binom[i - 1][2]); ln(E, G); for (int i = 1; i <= n; ++i) { G[i] = 0; for (int j = 0; j < i + 1; ++j) G[i] += binom[i][j] * pow(2, j * (i - j)); } ln(B1, G); for (int i = 1; i <= n; ++i) B1[i] /= 2; exp(B, B1); int T; cin >> T; while (T--) { cin >> n; cout << "Connected: " << C[n] << '\n' << "Eulerian: " << E[n] << '\n' << "Bipartite: " << B[n] << "\n\n"; }}
上述关于 EGF 的 exp 的用法,有时又被称作 Riddell’s formula for labeled graphs,生成函数的 欧拉变换,有时也被称为 Riddell’s formula for unlabeled graphs,后者最早出现在欧拉对分拆数的研究中,除了解决图论计数问题之外,也在完全背包问题中出现。
#include <iostream>#include <vector>using namespace std;using LL = long long;int MOD = int(1e9) + 7;namespace NT {void INC(int& a, int b) { a += b; if (a >= MOD) a -= MOD;}int sum(int a, int b) { a += b; if (a >= MOD) a -= MOD; return a;}void DEC(int& a, int b) { a -= b; if (a < 0) a += MOD;}int dff(int a, int b) { a -= b; if (a < 0) a += MOD; return a;}void MUL(int& a, int b) { a = (LL)a * b % MOD; }int pdt(int a, int b) { return (LL)a * b % MOD; }int _I(int b) { int a = MOD, x1 = 0, x2 = 1, q; while (1) { q = a / b, a %= b; if (!a) return x2; DEC(x1, pdt(q, x2)); q = b / a, b %= a; if (!b) return x1; DEC(x2, pdt(q, x1)); }}void DIV(int& a, int b) { MUL(a, _I(b)); }int qtt(int a, int b) { return pdt(a, _I(b)); }int pow(int a, LL b) { int c(1); while (b) { if (b & 1) MUL(c, a); MUL(a, a), b >>= 1; } return c;}template <class T>T pow(T a, LL b) { T c(1); while (b) { if (b & 1) c *= a; a *= a, b >>= 1; } return c;}template <class T>T pow(T a, int b) { return pow(a, (LL)b);}struct Int { int val; operator int() const { return val; } Int(int _val = 0) : val(_val) { val %= MOD; if (val < 0) val += MOD; } Int(LL _val) : val(_val) { _val %= MOD; if (_val < 0) _val += MOD; val = _val; } Int& operator+=(const int& rhs) { INC(val, rhs); return *this; } Int operator+(const int& rhs) const { return sum(val, rhs); } Int& operator-=(const int& rhs) { DEC(val, rhs); return *this; } Int operator-(const int& rhs) const { return dff(val, rhs); } Int& operator*=(const int& rhs) { MUL(val, rhs); return *this; } Int operator*(const int& rhs) const { return pdt(val, rhs); } Int& operator/=(const int& rhs) { DIV(val, rhs); return *this; } Int operator/(const int& rhs) const { return qtt(val, rhs); } Int operator-() const { return MOD - *this; }};} // namespace NTusing namespace NT;constexpr int N = int(5e1) + 9;Int Fact[N];vector<vector<int>> Partition;vector<int> cur;int n, m;void gen(int n = ::n, int s = 1) { if (!n) { Partition.push_back(cur); } else if (n >= s) { cur.push_back(s); gen(n - s, s); cur.pop_back(); gen(n, s + 1); }}Int w(const vector<int> P) { Int z = Fact[n]; int c = 0, l = P.front(); for (auto p : P) { z /= p; if (p != l) { z /= Fact[c]; l = p; c = 1; } else { ++c; } } z /= Fact[c]; return z;}int gcd(int x, int y) { return y ? gcd(y, x % y) : x; }int c(const vector<int> P) { int z = 0; for (int i = 0; i < P.size(); ++i) { z += P[i] / 2; for (int j = 0; j < i; ++j) z += gcd(P[i], P[j]); } return z;}int main() { cin >> n >> m >> MOD; Fact[0] = 1; for (int i = 1; i <= n; ++i) Fact[i] = Fact[i - 1] * i; gen(); Int res = 0; for (auto P : Partition) { res += w(P) * pow(m, c(P)); } res /= Fact[n]; cout << res << endl;}