【CF1671E】Preorder【计数】

这篇文章讲述了如何使用DFS算法解决子树乘以2并去除重复的问题,通过比较字典序来确定是否需要交换节点。代码示例展示了如何在C++中实现这一过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述

分析

赛时已经想到了子树*2的方法,但是没想到怎么去掉重复的东西,实际上已经很接近答案了。

在子树本质相同的时候,通过交换是没法*2的,所以就记录字典序,比较最小字典序是否相同,这个可以用DFS实现。

上代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll; 

const int mod=998244353;
int n,a[1000010],p;
string s[1000010];
ll f[1000010];

void dfs(int x)
{
	int ls=x*2,rs=x*2+1;
	if(ls>p) //叶子 
	{
	    s[x]=a[x]+'0';
		f[x]=1;
		return;	
	}
	dfs(ls);dfs(rs);
	if(s[ls]==s[rs]) f[x]=f[ls]*f[rs]%mod;
	else f[x]=f[ls]*f[rs]%mod*2%mod;
	s[x]=a[x]+'0';
	if(s[ls]<s[rs]) s[x]=s[x]+s[ls]+s[rs];//判字典序 
	else s[x]=s[x]+s[rs]+s[ls];
}

int main()
{
	cin>>n;
	p=pow(2,n)-1;
	for(int i=1;i<=p;i++) 
	{
		char c;
		cin>>c;
		if(c=='A') a[i]=1;
	}
	dfs(1);
	cout<<f[1];
	return 0;
}
我希望下面这段代码的树状打印(右子树在右,左子树在左)#include <stdio.h> #include <stdlib.h> // 二叉链表结构 typedef struct BTNode { char data; struct BTNode *lchild, *rchild; } BTNode; /* 核心功能实现 */ // 创建二叉树(扩展先序序列) BTNode* CreateBTree() { char ch; scanf("%c", &ch); if(ch == '#') return NULL; // #表示空节点 BTNode *node = (BTNode*)malloc(sizeof(BTNode)); node->data = ch; node->lchild = CreateBTree(); node->rchild = CreateBTree(); return node; } // 先序遍历 void PreOrder(BTNode *root) { if(root) { printf("%c ", root->data); PreOrder(root->lchild); PreOrder(root->rchild); } } // 中序遍历 void InOrder(BTNode *root) { if(root) { InOrder(root->lchild); printf("%c ", root->data); InOrder(root->rchild); } } // 后序遍历 void PostOrder(BTNode *root) { if(root) { PostOrder(root->lchild); PostOrder(root->rchild); printf("%c ", root->data); } } // 统计叶子节点 int CountLeaves(BTNode *root) { if(!root) return 0; if(!root->lchild && !root->rchild) return 1; return CountLeaves(root->lchild) + CountLeaves(root->rchild); } // 计算树高 int TreeHeight(BTNode *root) { if(!root) return 0; int leftH = TreeHeight(root->lchild); int rightH = TreeHeight(root->rchild); return (leftH > rightH ? leftH : rightH) + 1; } // 树状打印 void PrintTree(BTNode *root, int depth) { if(!root) return; PrintTree(root->rchild, depth + 1); // 按深度缩进 for(int i = 0; i < depth; i++) printf(" "); printf("%c\n", root->data); PrintTree(root->lchild, depth + 1); } // 查找路径 int FindPath(BTNode *root, char target, char path[], int *depth) { if(!root) return 0; path[(*depth)++] = root->data; // 记录当前节点 if(root->data == target) return 1; if(FindPath(root->lchild, target, path, depth) || FindPath(root->rchild, target, path, depth)) return 1; (*depth)--; // 回溯 return 0; } // 二叉排序树插入 BTNode* BST_Insert(BTNode *root, char key) { if(!root) { root = (BTNode*)malloc(sizeof(BTNode)); root->data = key; root->lchild = root->rchild = NULL; } else if(key < root->data) root->lchild = BST_Insert(root->lchild, key); else if(key > root->data) root->rchild = BST_Insert(root->rchild, key); return root; } /* 主函数 - 程序入口点 */ int main() { BTNode *root = NULL; int choice; char target; char path[100]; int depth = 0; printf("二叉树系统菜单:\n"); printf("1. 创建二叉树 (扩展先序序列,如 ABD##E##CF###)\n"); printf("2. 树状打印\n"); printf("3. 遍历 (先序/中序/后序)\n"); printf("4. 统计叶子节点\n"); printf("5. 计算树高\n"); printf("6. 查找路径\n"); printf("7. 创建二叉排序树\n"); printf("0. 退出\n"); while(1) { printf("\n请选择操作: "); scanf("%d", &choice); getchar(); // 清除输入缓冲区 switch(choice) { case 1: printf("输入扩展先序序列 (用#表示空节点): "); root = CreateBTree(); printf("二叉树创建成功!\n"); break; case 2: if(!root) { printf("请先创建二叉树!\n"); break; } printf("树状结构:\n"); PrintTree(root, 0); break; case 3: if(!root) { printf("请先创建二叉树!\n"); break; } printf("先序遍历: "); PreOrder(root); printf("\n中序遍历: "); InOrder(root); printf("\n后序遍历: "); PostOrder(root); printf("\n"); break; case 4: if(!root) { printf("请先创建二叉树!\n"); break; } printf("叶子节点数: %d\n", CountLeaves(root)); break; case 5: if(!root) { printf("请先创建二叉树!\n"); break; } printf("树高度: %d\n", TreeHeight(root)); break; case 6: if(!root) { printf("请先创建二叉树!\n"); break; } printf("输入目标节点: "); scanf("%c", &target); depth = 0; if(FindPath(root, target, path, &depth)) { printf("路径: "); for(int i = 0; i < depth; i++) { printf("%c", path[i]); if(i < depth-1) printf(" -> "); } printf("\n"); } else { printf("未找到节点 %c\n", target); } break; case 7: printf("输入节点序列 (空格分隔,回车结束): "); char ch; root = NULL; while(scanf("%c", &
最新发布
06-18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值