>Link
ybtoj最大匹配
>Description
n ≤ 1 0 5 n\le 10^5 n≤105
>解题思路
麻掉了,考试的时候修改代码没修改完全,直接100变70 qwq
因为在树上匹配,我们可以树形DP
设 f i f_i fi 为第 i i i个节点的子树中的最大匹配, f f i = ∑ j ∈ s o n ( i ) f j ff_i=\sum_{j\in son(i)}f_j ffi=∑j∈son(i)fj
如果选择一条边 ( u , v ) (u,v) (u,v) 且 u u u 是 v v v 的父亲, u u u 和 v v v 周围的其它边都不能选择,那当前的价值就为 f f v + f f u − f v + 1 ff_v+ff_u-f_v+1 ffv+ffu−fv+1,因为 f v f_v fv 不能加上但是 f f u ff_u ffu 里面包含了,所以要减去
最大匹配的数量也一样,跟着最大匹配一起修改
设 g i g_i gi 为 … 的最大匹配数量, g g i = ∏ j ∈ s o n ( i ) g i gg_i=∏_{j\in son(i)}g_i ggi=∏j∈son(i)gi
那 … 的情况下,方案数就为 g g v ∗ g g u / g v gg_v*gg_u/g_v ggv∗ggu/gv,原理同上,因为要取模,所以要处理一下逆元
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
#define LL long long
using namespace std;
const LL Mod = 1e9 + 7;
struct edge
{
int to, nxt;
} e[N * 2];
int T, P, n, cnt, h[N], f[N], ff[N], ans;
LL w[N], ww[N], answ;
void add (int u, int v)
{
e[++cnt] = (edge){
v, h[u]}; h[u] = cnt;
e[++cnt] = (edge){
u, h[v]}; h[v] = cnt;
}
LL power (LL aa, LL bb)
{
if (!aa) return 1;
LL ret = 1;
aa %= Mod;
for (; bb; bb >>= 1, aa = aa * aa % Mod)
if (bb & 1) ret = ret * aa % Mod;
return ret;
}
void dfs (int now, int fath)
{
int v, x = 0; LL y = 0;
for (int i = h[now]; i; i = e[i].nxt)
{
v = e[i].to;
if (v == fath) continue;
dfs (v, now);
ff[now] += f[v];
ww[now] = ww[now] * w[v] % Mod;
}
f[now] = ff[now], w[now] = ww[now];
for (int i = h[now]; i; i = e[i].nxt)
{
v = e[i].to;
if (v == fath) continue;
x = ff[v] + ff[now] - f[v] + 1;
y = ww[v] * ww[now] % Mod * power (w[v], Mod - 2) % Mod;
if (x > f[now]) f[now] = x, w[now] = y;
else if (x == f[now]) w[now] = (w[now] + y) % Mod;
}
}
void work ()
{
scanf ("%d", &n);
for (int i = 1; i <= n; i++)
h[i] = f[i] = ff[i] = 0, w[i] = ww[i] = 1;
ans = answ = cnt = 0;
int u, v;
for (int i = 1; i < n; i++)
{
scanf ("%d%d", &u, &v);
add (u, v);
}
dfs (1, 0);
if (f[1] > ans) ans = f[1], answ = w[1];
else if (f[1] == ans && ans) answ = (answ + w[1]) % Mod;
if (!ans) answ = 1;
if (P == 1) printf ("%d\n", ans);
else printf ("%d %lld\n", ans, answ);
}
int main()
{
freopen ("hungary.in", "r", stdin);
freopen ("hungary.out", "w", stdout);
scanf ("%d%d", &T, &P);
while (T--)
work ();
return 0;
}