Codeforces 1032F Vasya and Maximum Matching

Codeforces 1032F Vasya and Maximum Matching

题目链接

http://codeforces.com/contest/1032/problem/F

题目大意

给你一棵 $n$ 个节点的树,可以删除任意条边,使得删除完之后的图仅有一种最大匹配的方法。问有多少种删边方法。

题目分析

考虑使用树形 $DP$ 来解决这道题。如果最大匹配的方法是唯一的,说明任意拆出来一条链都是偶数个点的。设 $f[x][0/1]$ 分别为点 $x$ 和儿子中的一个匹配上了,和没匹配上任何一个儿子。则显然有

$$f[x][1] = \prod{(f[y][0] + f[y][1])}$$

再来考虑 $f[x][0]$ 的转移方程。很明显,如果 $x$ 和它的一个儿子匹配上的话显然要选取儿子 $y$ 的 $f[y][1]$ 。其余的点 $0$ 和 $1$ 都可以选。注意到, $y$ 的儿子中已经匹配上的儿子和 $x$ 中其他已经匹配上的儿子是可以和它们连边的,因此需要考虑这种情况统计一下即可。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>

using namespace std;

const int maxn = 3e5 + 5;

long long mod = 998244353;

int n, m, t;

vector <int> e[maxn];

long long f[maxn][2];
long long g[maxn];

int read(){
	int x;
	scanf("%d", &x);
	return x;
}

long long qpow(long long b, long long x){
	long long ret = 1;
	
	while(x){
		if(x & 1){
			ret = ret * b % mod;
		}
		
		b = b * b % mod;
		x >>= 1;
	}
	
	return ret;
}

int addedge(int x, int y){
	e[x].push_back(y);
	e[y].push_back(x);
	
	return 0;
}

int dfs(int x, int fa){
	int y;
	int i, j;
	
	f[x][0] = 0;
	f[x][1] = 1;
	g[x] = 1;
	
	for(auto y : e[x]){
		if(y != fa){
			dfs(y, x);
			f[x][1] = f[x][1] * ((f[y][0] + f[y][1]) % mod) % mod;
			g[x] = g[x] * ((2 * f[y][0] + f[y][1]) % mod) % mod;
		}
	}
	
	for(auto y : e[x]){
		if(y != fa){
			f[x][0] = (f[x][0] + (g[x] * qpow((2 * f[y][0] + f[y][1]) % mod, mod - 2) % mod) * g[y] % mod) % mod;
		}
	}
	
	return 0;
}

int main(){
	int i, j;
	int x, y;
	
	n = read();
	
	for(i=1;i<n;i++){
		x = read();
		y = read();
		
		addedge(x, y);
	}
	
	dfs(1, -1);
	
	printf("%lld\n", (f[1][0] + f[1][1]) % mod);
	
	return 0;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据