CACC 2025 Final
CACC 2025 Final
Day 0
A.
给定 \((a_i)_{i=0}^{n-1}\in(\mathbb{N}^*)^n\ (n\in\mathbb{N}^*)\),求区间乘积大于等于区间长度的区间数,即求满足
\[\prod_{i=b}^{e-1}a_i\geq e-b\ (b<e\leq n) \]的 \((b,e)\in\mathbb{N}^2\) 的数量。
保证 \(n\leq5\times10^5,\ \forall i\in\mathbb{N}\cap[0,n)\ (a_i\leq10^3)\)。
不知道怎么就过了。特判 is_all_one 是因为有 \(10\%\) 的测试点满足全为 \(1\),另有 \(10\%\) 的满足每个数要么为 \(1\) 要么为 \(2\) 。
inline void solve() {
size_t n;
std::cin >> n;
std::vector<uint64_t> arr(n);
bool is_all_one = true;
for (auto &e : arr) {
std::cin >> e;
if (e != 1) is_all_one = false;
}
if (is_all_one) {
std::cout << ((n * (n + 1)) >> 1) << '\n';
return;
}
uint64_t ans = ((n * (n + 1)) >> 1);
for (size_t i = 0; i < n; ++i) {
uint64_t prod = 1;
for (size_t j = i + 1; j < n; ++j) {
prod *= arr[j];
if (prod >= n - i) break;
if (prod < j - i + 1) --ans;
}
}
std::cout << ans << '\n';
}
B.
给定数轴上的 \(n\in\mathbb{N}^*\) 个点,坐标分别为 \(\vec{x}=(x_i)_{i=1}^n\in\mathbb{N}^n\)。为每个点分别指定一个非负实数 \(r_i\) 作为半径,使得
\[\forall i\in\mathbb{N}\cap[1,n)\ (x_i+r_i\leq x_{i+1}-r_{i+1}), \]求
\[\sum_{i=1}^nr_i \]的最大值。
保证 \(2\leq n\leq10^6\),\(\vec{x}\) 单调递增且 \(x_n\leq10^9\)。
这是一个 \(2n-1\) 条约束的整数规划问题:
但是除了得出这个名字以外没有甚么用。
我们只考虑后 \(n-1\) 条约束,也就是那些线段造成的约束。端点的半径只参与一条,其他的半径都参与两条,所以它们相对来说受到的限制更少、更自由。假如 \((r_1+r_2)\) 恰好等于 \((x_2-x_1)\),那末它们对最终结果的贡献之和就是 \((x_2-x_1)\)。然而由于 \(r_2\) 受到 \(r_2+r_3\leq x_3-x_2\) 的限制,有可能因为 \(r_2\) 取不了很长,但 \(r_1\) 只受这一条限制,所以只需 \(r_1\) 尽可能长,就能使 \((x_2-x_1)\) 全部贡献给结果。对 \(r_{n-1}\) 和 \(r_n\) 也是同理。所以考虑从外向内依次确定半径,尽可能使外侧的点的半径长。
注意讨论偶数个点和奇数个点,它们在最中间稍有不同。
C.
给定一颗有根树 \(T\),\(0\) 为根节点。记 \(t(v)\ (v\in V(T))\) 表示以 \(v\) 为根的子树。初始时,树上每个点有个空篮子。进行 \(m\in\mathbb{N}^*\) 次操作,第 \(i\in\mathbb{N}\cap[0,m)\) 次给定 \(a_i,b_i\in V(T)\),对 \(t(a_i)\cup t(b_i)\) 的每个点的篮子,放一颗颜色为 \(i\) 的果子。需要对每个 \(u\in V(T)\) 求出,有多少个 \(v\in V(T)\) 满足 \(u,v\) 的篮子中有同色的果子。
保证 \(2\leq n\leq 2\times10^5,\ m\leq10^5\)。
不会。用 std::bitset 写了个比较暴力的做法,拿了 \(50\) 分。
D.
卡池中有 \(m\in\mathbb{N}^*\) 张价值为 \((a_i)_{i=0}^{m-1}\in(\mathbb{N}^*)^m\) 的 A 类卡和 \(n\) 张价值为 \((b_i)_{i=0}^{n-1}\in(\mathbb{N}^*)^n\) 的 B 类卡。现在进行不放回随机抽卡,每张卡被抽中的概率正比于其价值。抽到卡池中 A 类卡抽完为止,求模 \(998244353\) 意义下抽出的总卡数的期望。
保证 \(1\leq m\leq1000,\ {\color{red}0}\leq n\leq100,\ \forall i\in\mathbb{N}\cap[0,m)\ (a_i\leq500),\ \forall i\in\mathbb{N}\cap[0,n)\ (b_i\leq10^8)\)。
不会。写了 \(n=0\) 的情况(答案为 \(m\)),得了 \(2.1\) 分,我不知道怎么得出来的。
E.
实现 Satlike-w 算法的
void flip(int flipvar)函数,优化其void local_search(std::vector<int> &init_solution)和int pick_var()函数。
给的傻逼代码下标越界了。傻逼 VS Code 频繁崩溃。调试也调试不了,只能用 gdb 命令行调试,但实在不方便,基本上都是古法调试。
写了 flip,本地测出来 \(60\sim70\) 分(总分 \(300\))。给 local_search 试了试加跳出局部最优,还没运行完比赛就结束了,幸好结果只有 \(27\) 分,不亏。这次优化题花了几个小时(因为 A,B 都 AC 了而 C,D 感觉确实想不出),感觉时间主要花在读题、读他的狗屎代码和运行上了。
Day 1
AI 题:模型轻量化挑战
看都看不懂,skip。
安全题:分布式广播
我认为这是极好的题。
形式有点类似经典竞赛中的通信题,由相同代码创建的多个实例之间要互相通信,只不过这里直接实现了 TCP 网络协议。
实现以下算法。
Q1. 尽力而为广播(Best-Effort Broadcast)
算法描述
网络中有若干节点,分别编号为 \(\mathbb{N}\cap[0,n)\)。节点之间通过网络传递消息。
每条消息在与应用层的接口上表现为
(const std::string &msg_id, const json &data)两个参数,即评测代码唤起 \(broadcast(msg)\) 事件和接受 \(deliver(msg)\) 时,消息 \(m\) 都由这两个参数提供。通过网络发送的消息为一个 JSON 对象,要求至少具有以下字段:
type: String:信息类型。signature: String:消息签名。发送信息前必须用自己的node_id和消息内容或哈希进行签名,以确保信息完整性。接收方也必须调用提供的verify接口进行校验。对同一条消息中的每个节点:
- 发生 \(broadcast(msg)\) 事件时:(系统会调用选手实现的
broadcast(const std::string &msg_id, const json &data)唤起选手代码)当前节点应向其他所有节点发送 \(send(msg)\) 消息(内容可以自行决定,但赛题提供了一些建议帮助理解)。发送信号可以调用赛题提供的send_to(int target, const json &content)或send_to_all(const json &content)。- 收到 \(send(msg)\) 消息时:如果收到的消息 \(m\) 还未提交过,就立刻提交( \(deliver(msg)\),选手代码调用提供的
deliver(const std::string &msg_id, const json &data))。广播事件的发生不会等待上一次广播的消息全部得到提交,即网络中可能有多条内容不同的消息在同时传播。赛题代码已经做了串行处理,无需加锁。
要求
- 有效性:诚实的节点的 \(broadcast(msg)\) 事件必定导致所有诚实的节点提交 \(msg\)。
- 不重复性:每个诚实的节点对同一条消息最多提交一次。
- 不创造性:呈示的节点不会凭空提交没被广播过的消息。
Q2. 认证回声广播(Authenticated Echo Broadcast)
部分节点表示出任意甚至恶意的现象称为拜占庭故障。认证回声广播可以一定程度上避免拜占庭故障。
算法描述
一共有 \(n=3f+1\) 个节点,其中 \(f\in\mathbb{N}\) 个是恶意节点。
对同一条消息中的每个节点:
维护一个向量 \(echo\_from\_nodes=(echo\_from\_node_i)_{i=0}^{n-1}\)。初始时全为空。
\(broadcast(msg)\) 事件的响应同 Q1.。
收到 \(send(msg)\) 消息时:向所有节点发送 \(echo(msg)\) 消息。
收到来自节点 \(src\) 的 \(echo(msg)\) 消息时:若 \(echo\_from\_node_{src}=\varnothing\),则令 \(echo\_from\_node_{src}\gets msg\);否则忽略。
如果存在消息 \(msg\) 满足
\[|\{src\in\mathbb{N}\cap[0,n):echo\_from\_node_{src}=msg\}|\geq2f+1, \]则提交 \(msg\)。
要求
在 Q1. 的基础上避免重复 \(echo\)。存在恶意节点时,保证有诚实节点不提交恶意节点发送的消息。
Q3. 拜占庭可靠广播(Byzantine Reliable Broadcast)
算法描述
在 Q2. 的基础上加一层 \(ready\) 检验:对某条消息,某个节点在收到回声数达到 \((2f+1)\) 时,还不提交,而是再向所有节点发送 \(ready(msg)\) 信号。同样维护一个初始全为空的向量 \(ready\_from\_nodes\),接收到 \(ready(msg)\) 时,以同样的方式保存。若存在消息 \(msg\) 满足
\[|\{src\in\mathbb{N}\cap[0,n):ready\_from\_node_{src}=msg\}|\geq f+1, \]则提交 \(msg\)。
要求
忘记了,总之会检查有没有真发 \(ready\) 消息,会不会重复 \(ready\)。
Q4. 优化认证回声广播
利用纠删码(erasure coding)优化认证回声广播。
算法描述
本题不涉及拜占庭故障。
指定参数 \(m\),利用 \(encode(m,n,msg)\) 可以将 \(msg\) 编码为 \(n\) 个块 \((s_i)_{i=0}^{n-1}\),且满足其中任意 \(m\) 块(设编号分别为 \((p_i)_{i=0}^{m-1}\))可以利用 \(decode((p_i,s_{p_i})_{i=0}^{m-1})\) 解码恢复为 \(msg\)。利用纠删码优化广播。提供哈希计算函数 \(SHA256\) 建议用 \(node\_id\) 和数据的哈希值签名而非直接用数据,以提高签名效率,因为反正内容中都要包括块信息,到时候数据会恢复出来的。
题目说这可以让每个节点的空间开销还是甚么降低为原来的 \(O\left(\dfrac{1}{m}\right)\)。
要求
忘了。
Q5. 优化拜占庭可靠广播
没有算法的描述
利用纠删码优化 Q3.。说是要用 Merkle tree,而且给了 Merkle tree 的描述,但说是要自己实现。
要求
同 Q3.。
大力表扬这道题给的代码。十分优雅!比昨天的优化题不知道好到那里去了。
Q1.~Q4. 照着写就行。Q1.~Q3. 都 AC 了,Q4. 不知道为甚么有 \(1/10\) 个点没过。Q5. 说要我优化,我管他甚么纠删码优化,直接开个 O3 就交了,也过了 \(9/10\) 个点。满意离场。

浙公网安备 33010602011771号