BZOJ 2560 及其加強
阿新 • • 發佈:2019-05-02
div args line 遞推 %d max std rgs cos
有$n$個點,在$i,j$兩個點之間連邊的方案數有$c_{i,j}$種,也可以不連。求不同的連通導出子圖個數(即有多少種連邊方案使得整個圖連通)。
$$n\le16$$
加強:
$$n\le20$$
令$g_S$為點集$S$的導出子圖個數,$f_S$為點集$S$的連通導出子圖個數。特別地,$f_{\varnothing}=g_{\varnothing}=0$。
$g$是好求的,由定義知
$$g_S=\prod_{i,j\in S}c_{i,j}+1$$
可以$O(n2^n)$求。
考慮怎麽求$f$,在$n\le16$時,直接子集$\text{dp}$算不連通導出子圖個數即可,即
$$f_S=g_S-\sum_{1 \in T \land T \subset S}f_Tg_{S\setminus T}$$
時間復雜度$O(3^n)$。
但在$n$更大的時候,這個復雜度是不可接受的。
考慮集合冪級數,定義乘法為子集卷積,則
$$1+g=\sum_{k\ge0}\frac{f^k}{k!}$$
即
$$1+g=e^f$$
轉換一下,得
$$f=\ln(1+g)$$
那麽對$g$做$\text{FMT}$之後對每一項暴力遞推求$\ln$即可。
時間復雜度$O(n^22^n)$。
1 #include <bits/stdc++.h> 2 3 #define IL __inline__ __attribute__((always_inline)) 45 #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) 910 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...\n", __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\n", f[(1 << n) - 1][n]); 153 return 0; 154 }
BZOJ 2560 及其加強