Masha and a Beautiful Tree
题意:
一棵完全的二叉树,在这棵二叉树的最后一行,有一段序列,现在他给的这个序列是乱序的,你有一种操作,可以交换一个二叉树节点的左右两边的儿子,最后使得最后的序列是递增的,问最少的操作次数,如果不行的话就输出-1
思路:
首先,先如果去模拟这个过程,时间上不行,而且这个操作也十分难写,所以肯定不是去模拟这个操作,那肯定是可以从题目中推导出一些结论,然后根据这些结论来写代码
- m如果是1直接0,如果不是1必须二进制分解只能出现一个1,这里可以用__builtin_popcount()来快速求
- 因为最后是递增的,所以比如有8个叶子节点,4个4个分组,1, 2, 3, 4必须在一个组,5, 6, 7, 8必须在一个组,所以这里就要有一个快速判断了,可能这里就有结论,当时就是没想到,这里的结论就是,对于左右两端,假设左端的数字和为num1, 右端的数字和为num2, 那abs(num2 - num1) == k * k, 这里的k就是要交换节点和层数有关了,比如要交换4个4个,那k == 4, 以此类推,知道了这个规律,这个规律可以用前缀和来维护,就可以二分的取分治,然后求出答案,在分治的同时判断是否合法
结论:
如果一个地方时间复杂度可能超时,那很有可能是有结论的,通过这个结论就可以一步得出
点击查看代码
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);
#define endl '\n'
using namespace std;
typedef long long ll;
const int MAXN = 262144 + 10;
ll T, m, ans = 0;
ll p[MAXN];
ll sum[MAXN];
bool flag = true;
void init()
{
ans = 0, flag = true;
for (int i = 1; i <= m; ++i)
sum[i] = 0;
}
void dfs(ll l, ll r, ll k)
{
if (l == r)
return ;
if (r - l == 1)
{
if (abs(p[r] - p[l]) == 1)
{
if (p[r] < p[l])
++ans;
return ;
}
else
{
flag = false;
return ;
}
}
ll mid = (l + r) >> 1;
ll head = sum[mid] - sum[l - 1];
ll end = sum[r] - sum[mid];
if (abs(end - head) == k * k)
{
if (end < head)
++ans;
dfs(l, mid, k / 2);
dfs(mid + 1, r, k / 2);
}
else
{
flag = false;
return ;
}
}
int main()
{
IOS; cin.tie(0), cout.tie(0);
cin >> T;
while (T--)
{
cin >> m;
init();
for (int i = 1; i <= m; ++i)
cin >> p[i], sum[i] = sum[i - 1] + p[i];
if (m == 1)
{
cout << "0" << endl;
continue;
}
if (m & 1 || __builtin_popcount(m) != 1)
{
cout << "-1" << endl;
continue;
}
dfs(1, m, m / 2);
cout << (flag == true ? ans : -1) << endl;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!