题面
解法
似乎是容斥原理的套路题???
- 对于每一个公司恰好修建一条边这个条件似乎并没有那么好处理,那么我们不妨考虑容斥原理
- 答案可以先加上 n − 1 n-1 n−1个公司可以随便选的方案数,然后发现 n − 2 n-2 n−2个公司随便选的情况被重复统计了,减去 n − 2 n-2 n−2个公司的方案数,然后再加上 n − 3 n-3 n−3个公司的方案数……这样一直做下去即可
- 现在问题就转化成,如何求给定的 x x x个公司随便选的方案??
- 可以发现这是一个求生成树个数的问题,可以使用矩阵树定理解决
- 时间复杂度: O ( 2 n − 1 n 3 ) O(2^{n-1}n^3) O(2n−1n3)
代码
#include <bits/stdc++.h>
#define Mod 1000000007
#define N 600
using namespace std;
template <typename node> void chkmax(node &x, node y) {x = max(x, y);}
template <typename node> void chkmin(node &x, node y) {x = min(x, y);}
template <typename node> void read(node &x) {
x = 0; int f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
struct Node {
int x, y, id;
} a[N * N];
int b[N][N];
int lowbit(int x) {return x & -x;}
int calc(int x) {
int ret = 0;
while (x) x -= lowbit(x), ret++;
return ret;
}
int Pow(int x, int y) {
int ret = 1;
while (y) {
if (y & 1) ret = 1ll * ret * x % Mod;
y >>= 1, x = 1ll * x * x % Mod;
}
return ret;
}
int gauss(int n) {
int ans = 1;
for (int i = 2; i <= n; i++) {
if (!b[i][i])
for (int j = i + 1; j <= n; j++)
if (b[j][i]) {
for (int k = 2; k <= n; k++) swap(b[j][k], b[i][k]);
ans = Mod - ans; break;
}
int x = Pow(b[i][i], Mod - 2);
for (int j = i + 1; j <= n; j++)
if (b[j][i]) {
int t = 1ll * b[j][i] * x % Mod;
for (int k = 2; k <= n; k++) b[j][k] = (b[j][k] - 1ll * t * b[i][k] % Mod + Mod) % Mod;
}
}
for (int i = 2; i <= n; i++) ans = 1ll * ans * b[i][i] % Mod;
return (ans + Mod) % Mod;
}
int main() {
int n, tot = 0; read(n);
for (int i = 1; i < n; i++) {
int k; read(k);
while (k--) {
int x, y; read(x), read(y);
a[++tot] = (Node) {x, y, i};
}
}
int ans = 0;
for (int i = 0; i < (1 << n - 1); i++) {
int t = calc(i);
for (int j = 1; j <= n; j++)
for (int k = 1; k <= n; k++)
b[j][k] = 0;
for (int j = 1; j <= tot; j++)
if (((i >> a[j].id - 1) & 1) == 1) {
b[a[j].x][a[j].y]--, b[a[j].y][a[j].x]--;
b[a[j].x][a[j].x]++, b[a[j].y][a[j].y]++;
}
for (int j = 1; j <= n; j++)
for (int k = 1; k <= n; k++)
if (b[j][k] < 0) b[j][k] += Mod;
int tmp = gauss(n);
if ((n - 1 - t) % 2 == 0) ans = (ans + tmp) % Mod;
else ans = (ans - tmp + Mod) % Mod;
}
cout << ans << "\n";
return 0;
}