0%

[ABC264Ex] Perfect Binary Tree

一个比较简单的 dp。

从暴力到正解实际上只有一个第一眼感觉没用的小优化。

题目链接。

题意

给了你一棵有根树,现在让你在 中选一些点,满足以下要求:

  1. 需要被选;
  2. 所有被选的点构成了一棵以 为根的完美二叉树(所有叶子深度一样)。

对于每一个 ,输出答案。

题解

对于每一个节点 ,我们用 表示以 为根的,深度为 的完美二叉树个数。

我们对于每一个 ,重新跑一边dp。

这样子时间复杂度是 的,状态 ,转移均摊 ,还要转移 ,显然过不了。

显然,可以优化一下转移,大概就是对于每一个节点,求一下儿子的 之和。

然后,我们直接枚举一个儿子进行转移就彳亍,不用枚举两个。

这样这个dp就成 的了。

你还会发现,每一次多出来一个点,对他祖先们的dp值,只有一个 发生了变化,我们直接只转移变化的这一位。

时间复杂度是 。

然后你会发现,一棵深度为 的二叉树,节点数高达 。

这题一共就 个节点,二叉树深度最多也就 。

所以对于深度大于 的点,直接不处理了。

同时,对于 的部分,我们也不用处理了。

时间复杂度 。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<map>
using namespace std;
const int mod=998244353;
using ll=long long;
using pli=pair<ll,int>;
using pi=pair<int,int>;
template<typename A>
using vc=vector<A>;
inline int read()
{
int s=0,w=1;char ch;
while((ch=getchar())>'9'||ch<'0') if(ch=='-') w=-1;
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
template<const int N,const int M>
struct graph
{
int head[N+5];
int t[M+5];
int x[M+5];
int cntm;
graph(){ cntm=1;}
void clear(int n=N)
{
cntm=1;
for(int i=1;i<=n;i++) head[i]=0;
}
void ad(int u,int v)
{
cntm++;
t[cntm]=v;
x[cntm]=head[u];
head[u]=cntm;
}
void add(int u,int v)
{
ad(u,v);
ad(v,u);
}
int st(int num){ return head[num];}
int to(int num){ return t[num];}
int nx(int num){ return x[num];}
};
graph<300000,600000>g;
ll son[300001][21];
ll dp[300001][21];
int dep[300001];
int fa[300001];
int n;
void dfs(int num)
{
for(int i=g.st(num);i;i=g.nx(i))
{
int p=g.to(i);
if(p==fa[num]) continue;
dep[p]=dep[num]+1,fa[p]=num,dfs(p);
}
}
int main()
{
n=read();
for(int i=2;i<=n;i++) g.add(read(),i);
dfs(1);
for(int i=1;i<=n;i++)
{
if(dep[i]<=20)
{
dp[i][0]=1;ll delta=1;
for(int j=1,nod=fa[i],lst=i;nod;j++,nod=fa[nod],lst=fa[lst])
{
(son[nod][j-1]+=delta)%=mod;
delta=(son[nod][j-1]-dp[lst][j-1]+mod)*delta%mod;
dp[nod][j]=(dp[nod][j]+delta)%mod;
}
}
ll ans=0;
for(int i=0;i<=20;i++) ans=(ans+dp[1][i])%mod;
printf("%lld\n",ans);
}
return 0;
}