描述
题解
真的感觉这个题好难,看了官方题解也不知道怎么搞,又找了一下代码,稍微懂了一些……总得来说,这个题就是 dp (树归、状压) + 贪心,贴一下官方题解吧……我也说不好。真废……
代码
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef vector<int>::iterator vit;
const int MAXN = 1e5 + 10;
const int MAX_LEAF = 20;
const int MOD = 1e9 + 7;
int n;
int tot = 0, ans = 1;
int f[MAXN];
int g[1 << MAX_LEAF];
int p[1 << MAX_LEAF];
double h[1 << MAX_LEAF];
vector<int> e[MAXN];
template <class T>
inline void scan_d(T &ret)
{
char c;
ret = 0;
while ((c = getchar()) < '0' || c > '9');
while (c >= '0' && c <= '9')
{
ret = ret * 10 + (c - '0'), c = getchar();
}
}
void dfs(int u, int pre)
{
for (vit it = e[u].begin(); it != e[u].end(); ++it)
{
int v = *it;
if (v == pre)
{
continue;
}
dfs(v, u);
f[u] |= f[v];
}
if (!f[u])
{
f[u] = 1 << tot++;
}
g[f[u]]++;
}
int main()
{
scan_d(n);
int u, v;
for(int i = 1; i < n; ++i)
{
scan_d(u), scan_d(v);
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1, -1);
int tmp;
reverse(g, g + (1 << tot));
for (int i = 0; i < tot; ++i)
{
tmp = 1 << i;
for (int j = 1; j < 1 << tot; ++j)
{
if (j & tmp)
{
g[j] += g[j ^ tmp];
}
}
}
reverse(g, g + (1 << tot));
for (int i = 0; i < tot; ++i)
{
tmp = 1 << i;
for (int j = 1; j < 1 << tot; ++j)
{
if (j & tmp)
{
g[j] = g[j ^ tmp] - g[j];
}
}
}
memset(p, -1, sizeof(p));
for (int i = 1; i < 1 << tot; ++i)
{
for (int j = 0; j < tot; ++j)
{
tmp = 1 << j;
if ((i & tmp) && (p[i] == -1 || h[i] < h[i ^ tmp]))
{
h[i] = h[i ^ tmp];
p[i] = j;
}
}
h[i] += log(g[i] + 1);
}
for (int i = (1 << tot) - 1; i; i ^= 1 << p[i])
{
ans = ans * (g[i] + 1LL) % MOD;
}
printf("%d\n", ans);
return 0;
}