BZOJ 2560 及其加强

有$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))
  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...\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 }

 

posted @ 2019-05-02 11:42  sjkmost  阅读(276)  评论(0编辑  收藏  举报