CF EDU 127 E - Preorder
E - Preorder
树形dp
若两颗满二叉树深度相同,一颗二叉树交换任意两个兄弟结点及其子树可以得到另一颗二叉树,则成这两颗二叉树同构
设 u 的左右儿子为 ls,rs
- 若 ls 与 rs 同构,则
- 否则,ls,rs 交换又是一种新方案,
关键为如何判断两颗二叉树同构
性质:设二叉树有 n 个结点,每个结点的子树大小之和是 nlogn 级别
证明:设深度为 h,,
因此约为 nlogn
所以可以求出所有结点的子树的字符串,即并规定左子树字典序 < 右子树,这样直接看两个子树对应的字符串是否相等就可以判断是否同构
求结点深度时如果用 log 函数,注意精度误差
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <map>
#define ls u << 1
#define rs u << 1 | 1
#define log2(x) (log(x) / log(2))
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int mod = 998244353;
const int N = 1 << 19;
const double eps = 1e-8;
int n;
string str, s[N];
ll f[N];
//给出结点编号求其在完全二叉树上的编号
int get_h(int u)
{
double ans = log2(u + 1);
//避免精度误差
if (abs(ans - round(ans)) < eps)
return ans;
return ceil(ans);
}
ll dfs(int u)
{
//判断是否为叶子结点
if (get_h(u) == n) // if((u << 1) >= (1 << n)) 更好
{
s[u] = str[u];
return 1;
}
if (f[u])
return f[u];
ll ans = dfs(ls) * dfs(rs) % mod;
if (s[ls] != s[rs])
ans = ans * 2 % mod;
if (s[ls] > s[rs])
swap(s[ls], s[rs]);
s[u] = str[u] + s[ls] + s[rs];
return f[u] = ans;
}
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> str;
str = " " + str;
cout << dfs(1) << endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!