有$n$个点,在$i,j$两个点之间连边的方案数有$c_{i,j}$种,也可以不连。求不同的连通导出子图个数(即有多少种连边方案使得整个图连通)。
$$nle16$$
加强:
$$nle20$$
令$g_S$为点集$S$的导出子图个数,$f_S$为点集$S$的连通导出子图个数。特别地,$f_{varnothing}=g_{varnothing}=0$。
$g$是好求的,由定义知
$$g_S=prod_{i,jin S}c_{i,j}+1$$
可以$O(n2^n)$求。
考虑怎么求$f$,在$nle16$时,直接子集$ ext{dp}$算不连通导出子图个数即可,即
$$f_S=g_S-sum_{1 in T land T subset S}f_Tg_{Ssetminus T}$$
时间复杂度$O(3^n)$。
但在$n$更大的时候,这个复杂度是不可接受的。
考虑集合幂级数,定义乘法为子集卷积,则
$$1+g=sum_{kge0}frac{f^k}{k!}$$
即
$$1+g=e^f$$
转换一下,得
$$f=ln(1+g)$$
那么对$g$做$ ext{FMT}$之后对每一项暴力递推求$ln$即可。
时间复杂度$O(n^22^n)$。
1 #include <bits/stdc++.h> 2 3 #define IL __inline__ __attribute__((always_inline)) 4 5 #define For(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++ i) 6 #define FOR(i, a, b) for (int i = (a), i##end = (b); i < i##end; ++ i) 7 #define Rep(i, a, b) for (int i = (a), i##end = (b); i >= i##end; -- i) 8 #define REP(i, a, b) for (int i = (a) - 1, i##end = (b); i >= i##end; -- i) 9 10 typedef long long LL; 11 12 template <class T> 13 IL bool chkmax(T &a, const T &b) { 14 return a < b ? ((a = b), 1) : 0; 15 } 16 17 template <class T> 18 IL bool chkmin(T &a, const T &b) { 19 return a > b ? ((a = b), 1) : 0; 20 } 21 22 template <class T> 23 IL T mymax(const T &a, const T &b) { 24 return a > b ? a : b; 25 } 26 27 template <class T> 28 IL T mymin(const T &a, const T &b) { 29 return a < b ? a : b; 30 } 31 32 template <class T> 33 IL T myabs(const T &a) { 34 return a > 0 ? a : -a; 35 } 36 37 const int INF = 0X3F3F3F3F; 38 const double EPS = 1E-8, PI = acos(-1.0); 39 40 #define DEBUG(...) fprintf(stderr, __VA_ARGS__) 41 #define OK DEBUG("Passing [%s] in LINE %d... ", __FUNCTION__, __LINE__) 42 43 const int MASK = 20, MOD = 1000000007; 44 45 IL int add(int a, int b) { 46 a += b; 47 return a >= MOD ? a - MOD : a; 48 } 49 50 IL int sub(int a, int b) { 51 a -= b; 52 return a < 0 ? a + MOD : a; 53 } 54 55 IL int mul(int a, int b) { 56 return (LL)a * b % MOD; 57 } 58 59 IL int quickPow(int a, int p) { 60 int result = 1; 61 for (; p; p >>= 1, a = mul(a, a)) { 62 if (p & 1) { 63 result = mul(result, a); 64 } 65 } 66 return result; 67 } 68 69 typedef int PowerSeries[MASK + 1]; 70 71 PowerSeries f[1 << MASK]; 72 int g[1 << MASK], val[MASK][MASK], inv[MASK + 1], n; 73 74 IL void add(PowerSeries &a, const PowerSeries &b) { 75 For(i, 0, n) { 76 a[i] = add(a[i], b[i]); 77 } 78 } 79 80 IL void sub(PowerSeries &a, const PowerSeries &b) { 81 For(i, 0, n) { 82 a[i] = sub(a[i], b[i]); 83 } 84 } 85 86 IL void FMT(PowerSeries *f) { 87 FOR(i, 0, n) { 88 FOR(S, 0, 1 << n) { 89 if (S & (1 << i)) { 90 add(f[S], f[S ^ (1 << i)]); 91 } 92 } 93 } 94 } 95 96 IL void IFMT(PowerSeries *f) { 97 FOR(i, 0, n) { 98 FOR(S, 0, 1 << n) { 99 if (S & (1 << i)) { 100 sub(f[S], f[S ^ (1 << i)]); 101 } 102 } 103 } 104 } 105 106 IL void ln(PowerSeries &f) { 107 PowerSeries tp; 108 memcpy(tp, f, sizeof f); 109 FOR(i, 1, n) { 110 int cur = 0; 111 FOR(j, 0, i) { 112 cur = add(cur, mul(j + 1, mul(f[j + 1], tp[i - j]))); 113 } 114 cur = mul(cur, inv[i + 1]); 115 f[i + 1] = sub(f[i + 1], cur); 116 } 117 } 118 119 int main() { 120 scanf("%d", &n); 121 For(i, 1, n) { 122 inv[i] = quickPow(i, MOD - 2); 123 } 124 FOR(i, 0, n) { 125 FOR(j, 0, n) { 126 scanf("%d", &val[i][j]); 127 val[i][j] = add(val[i][j], 1); 128 } 129 } 130 g[0] = 1; 131 FOR(S, 1, 1 << n) { 132 int last = 0; 133 FOR(i, 0, n) { 134 if (S & (1 << i)) { 135 last = i; 136 } 137 } 138 g[S] = g[S - (1 << last)]; 139 FOR(i, 0, last) { 140 if (S & (1 << i)) { 141 g[S] = mul(g[S], val[i][last]); 142 } 143 } 144 f[S][__builtin_popcount(S)] = g[S]; 145 } 146 g[0] = 0; 147 FMT(f); 148 FOR(i, 0, 1 << n) { 149 ln(f[i]); 150 } 151 IFMT(f); 152 printf("%d ", f[(1 << n) - 1][n]); 153 return 0; 154 }