基础认知
一、二叉树种类:
1.满二叉树。记深度k,节点数量2^k-1。
2.完全二叉树:除了底层,其余全满,底部从左到右连续。
3,平衡二叉搜索树:左子树和右子树高度差不大于1。
二、存储方式:
顺序存储:已知代码i的元素,其左右“孩子”代码为2i和2i+1。
三、遍历方式:
1.深度优先搜索(前中后序遍历)【递归】【迭代】
前:中左右;中:左中右;后:左右中。
2.广度优先遍历(层序遍历)【迭代】
奇点杯试题分析
1.高效求和判断完全平方数
#include <iostream>
#include <cmath>
using namespace std;
typedef long long ll;
// 计算满足条件的数对数量
ll count_pairs(ll n) {
ll total = 0; // 用于存储结果
const ll s_limit = 2 * n; // 两个数的最大和
ll k_max = static_cast<ll>(sqrt(s_limit)); // 最大可能的平方根
// 确保 k_max 是最大的满足 k_max^2 <= s_limit 的整数
while ((k_max + 1) * (k_max + 1) <= s_limit) ++k_max;
// 遍历所有可能的完全平方数
for (ll k = 2; k <= k_max; ++k) {
const ll s = k * k; // 当前完全平方数
const ll a = max(1LL, s - n); // i 的最小值
const ll b = (s - 1) / 2; // i 的最大值
if (a <= b) {
total += b - a + 1; // 累加满足条件的数对数量
}
}
return total;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
ll n;
cin >> n; // 输入 n
cout << count_pairs(n) << "\n"; // 输出结果
return 0;
}
难点:使用暴力法会TLE.不能使用多重循环。
2.计算连续子数组元素之和
#include <iostream>
using namespace std;
typedef long long ll;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
ll n;
cin >> n; // 输入数组长度
ll total = 0; // 用于存储最终结果
for (ll i = 1; i <= n; ++i) {
ll x;
cin >> x; // 逐个输入数组元素
total += x * i * (n - i + 1); // 计算当前元素的贡献并累加
}
cout << total << "\n"; // 输出结果
return 0;
}
难点:不能直接使用数组存放元素,会造成段错误。
3. DSU算法
#include<bits/stdc++.h>
using namespace std;
int n, m, k;
int fa[100005]; // 并查集数组
// 查找函数,带路径压缩
int find(int x) {
if (fa[x] == x) return fa[x]; // 如果 x 是自己的父节点,直接返回
else return fa[x] = find(fa[x]); // 否则递归查找,并压缩路径
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T = 1;
cin >> T; // 读取测试数据组数
while (T--) {
cin >> n >> m; // 读取节点数 n 和边数 m
// 初始化并查集
for (int i = 1; i <= n; ++i)
fa[i] = i;
// 读取 m 条边并合并集合
for (int i = 1; i <= m; ++i) {
int x, y;
cin >> x >> y;
int xx = find(x), yy = find(y); // 查找 x 和 y 的根节点
if (xx == yy) continue; // 如果已经在同一个集合,跳过
fa[xx] = yy; // 合并集合
}
cin >> k; // 读取查询数 k
int st;
cin >> st; // 读取起始节点 st
st = find(st); // 查找 st 的根节点
bool flag = 1; // 标志位,表示所有查询节点是否与 st 在同一个集合
// 检查接下来的 k-1 个节点
for (int i = 2; i <= k; ++i) {
int ed;
cin >> ed; // 读取查询节点
ed = find(ed); // 查找 ed 的根节点
flag &= (st == ed); // 检查是否与 st 在同一个集合
}
// 输出结果
puts(flag ? "YES" : "NO");
}
return 0;
}
4.计算因子并统计次数
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
const int MAX_A = 2e5 + 10;
vector<int> get_factors(int v) {
vector<int> res;
for (int i = 1; i * i <= v; ++i) {
if (v % i == 0) {
res.push_back(i);
if (i != v / i) {
res.push_back(v / i);
}
}
}
return res;
}
int cnt[MAX_A];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
long long ans = 0;
for (int v : a) {
auto factors = get_factors(v);
long long sum = 0;
for (int x : factors) {
sum += cnt[x];
}
sum %= MOD;
ans = (ans + sum) % MOD;
cnt[v] = (cnt[v] + 1) % MOD; // 只增加当前元素的计数
}
cout << ans << endl;
return 0;
}