CF1146F Leaf Partition 题解

Posted (≧ ω ≦) の小窝

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1146F Leaf Partition 题解相关的知识,希望对你有一定的参考价值。

一道优秀的树形 \\(\\textdp\\) 题目。

题意

首先简化一下题意。

求的是一颗有根树的连通块划分方案。

思路

观察题目,由于要统计方案,所以很容易确定是树形 \\(\\textdp\\) 题目。

但树形 \\(\\textdp\\) 的式子还是值得思考一下的。

我们可以设 \\(f_x,0\\) 表示与父亲相连的方案数,\\(f_x,1\\) 表示不与父亲相连的方案数。

这样还是无法快速转移。

我们可以再设 \\(g_x,0\\) 表示与 \\(0\\) 个儿子相连。

\\(g_x,1\\) 表示与 \\(1\\) 个儿子相连。

\\(g_x,2\\) 表示与 \\(2\\) 个儿子相连。

我们会发现,没有与儿子相连的点,必然不会在连通块内,所以必须不与父亲相连。

而只与一个儿子相连的点那么必然要与父亲相连,因为下面的叶子节点肯定会对应其他子树中的一个叶子节点。

而有两个儿子以上的点则可以随意。

所以:

\\[f_x,0=(g_x,0+g_x,2) \\]

\\[f_x,1=(g_x,1+g_x,2) \\]

此时,\\(\\textdp\\) 就能进行转移了。

复杂度:\\(O(n)\\)

Code

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int maxn = 200010;
const int mod  = 998244353;

int n , f[maxn][2] , g[3];

/*
f[i][1] 与父亲相连 
f[i][0] 不与父亲相连。
g[0] 合并0个儿子 g[1] 合并1个儿子 g[2] 合并2个儿子
*/

vector<int> son[maxn];

inline int read()

    int asd = 0 , qwe = 1; char zxc;
    while(!isdigit(zxc = getchar())) if(zxc == \'-\') qwe = -1;
    while(isdigit(zxc)) asd = asd * 10 + zxc - \'0\' , zxc = getchar();
    return asd * qwe;


signed main()

    n = read() ;
    for(int i = 2;i <= n;i++) son[read()].push_back(i);
	for(int i = n;i >= 1;i--)
	
		if(son[i].empty()) f[i][1] = f[i][0] = 1;
		else
		
			int g0 = 1 , g1 = 0 , g2 = 0;
			for(auto j : son[i])
				g[0] = g0 * f[j][0],
				g[1] = g0 * f[j][1] + g1 * f[j][0],
				g[2] = g1 * f[j][1] + g2 * f[j][0] + g2 * f[j][1],
				g[0] %= mod , g[1] %= mod , g[2] %= mod,
				g0 = g[0] , g1 = g[1] , g2 = g[2];
			f[i][0] = (g[0] + g[2]) % mod , f[i][1] = (g[1] + g[2]) % mod;
		
	
	cout << f[1][0];
    return 0;



以上是关于CF1146F Leaf Partition 题解的主要内容,如果未能解决你的问题,请参考以下文章

CF - 1110F Nearest Leaf

CF830CBamboo Partition 分块

CF932FEscape Through Leaf 启发式合并set维护凸包

CF932GPalindrome Partition(回文树,动态规划)

[CF1603D]Artistic Partition

CF932GPalindrome Partition 回文自动机