Codeforces Round 935 (Div. 3)

链接 https://codeforces.com/contest/1945

G. Cook and Porridge

小清新双队列模拟

大意:
\(n\) 个学生顺序排成一队等待吃饭,第 \(i\) 个学生优先级为 \(k_i\) ,吃饭时间为 \(s_i\) 。总共有 \(D\) 分钟的吃饭时间,每分钟厨师只能发出一份饭。
当第 \(i\) 个学生成为队首,时间为 \(x\) ,他可以立刻领取一份饭并出队,然后在第 \(x + s\) 时间回到队伍后面。若他前面一个编号为 \(j\) 的学生的优先级 \(k_j < k_i\) ,则 \(j\) 要让 \(i\) 排到前面。若同一分钟内有多个学生返回,则 \(s\) 更小的先返回。
询问当所有学生都至少吃到一份饭时的最小时间,或回答 \(D\) 分钟内不可能所有人都吃得到饭。

题解:
小清新双队列模拟。
首先若同一分钟有多个学生归队,他们的 \(s\) 一定两两不同,因为一分钟只能发出一份饭。

让原队列为 \(que1\) ,队首 \(front\) 。下标 \(1\) 到下标 \(front - 1\) 的学生存储在队列 \(que2\) 中。\(que1\) 是正常队列,\(que2\) 是优先队列。两个队列共用一个队首操作。

枚举时间 \(i \in [1, D]\) 。考虑队首操作、归队操作、结束。
不妨设 \(que1\) 队首学生为 \(x1\)\(que2\) 队首学生为 \(x2\)
1.当前队首操作会有两种情况:

  1. \(que2 = \emptyset\) 或者 \(x1\) 的优先级高于 \(x2\) ,则此时需要操作的是 \(x1\)
    1. 若 \(front = n\)\(x1\) 拿到饭后所有学生都至少吃到一份饭,答案为 \(i\) 。程序结束。
    2. 若 \(front \neq n\) ,设 \(x\) 的吃饭时间为 \(s\) ,则将 \(x\) \(push\)\(time(i + s)\) 中,然后 \(front := front + 1\)

  2. \(que2 \neq \emptyset\) ,且 \(y\) 优先级高于 \(x\) ,则实际上此时 \(y\)\(x\) 前面,设 \(y\) 的吃饭时间为 \(s\) ,则将 \(y\) \(push\)\(time(i + s)\) 中。

  3. 当前归队操作
    枚举 \(time[i]\) 的所有元素,加入 \(que2\) 。发饭是立即的,归队操作优先级要低于队首操作。

  4. 结束
    当前时间结束,到下一分钟。\(i := i + 1\)

遗留问题是优先级的重载,由于 STL 特性通常需要重载小于号。

对每个学生封装成一个 \(student\) ,有成员参数 \(s, k, t\) 代表“吃饭时间”、“优先级”、“归队时间”。
第一关键字为 \(k\)\(k\) 越小优先级越小。
第二关键字为 \(t\)\(k\) 相同时 \(t\) 越大优先级越小。
第三关键字为 \(s\)\(k, t\) 相同时 \(s\) 越大优先级越小。

H. GCD is Greater

小清新位贡献数学

大意:
给两个正整数 \(n\)\(x\) ,然后给一个长为 \(n\) 的数组 \(a\)\(A\) 从数组中选出 \(2 \sim n - 2\) 个元素并且计算连续 \(gcd\)\(B\) 计算剩下的数的连续 \(ADN\) ,并 \(ADN\)\(x\)
询问 \(A\) 的结果是否可以严格大于 \(B\) 的结果。如果可以,输出 \(A\)\(B\) 选择的数。

\(4 \leq n \leq 4 \cdot 10^{5}, 0 \leq x \leq 4 \cdot 10^{5}, 1 \leq a_i \leq 4 \cdot 10^{5}\)

题解:
\(A\) 的结果为 \(resA\) ,让 \(B\) 的结果为 \(retB\)

观察一: 单调性。gcd 和 ADN 随数增多均为递减趋势。于是 A 需要且只需要选两个数。选更多数结果不会更优。

暴力复杂度为 \(T(\binom{n}{2}) = O(n^{2})\)

观察二: 拆位贡献。拆位的角度下观察每个数,假设当前是针对 \(d\) 个数位。

  1. 若所有数是 \(1\)\(retB\) 一定是 \(1\)
  2. 若有一个 \(0\)\(retA\) 中有一个是这个数,则 \(retB\)\(1\) ,否则是 \(0\)
  3. 若有两个 \(0\)\(retA\) 中两个恰为这两个数,则 \(retB\)\(1\) ,否则是 \(0\)
  4. 若大于两个 \(0\)\(retB\) 一定是 \(0\)

对于情况 \(1, 2\) ,将对应数的位置 \(p\) 加入一个集合 \(S\)\(|S| = O(\log n)\)
由于会拆出 \(\log n\) 个数位,每次查询需要 \(O(n)\) ,于是获取 \(S\) 的时间复杂度为 \(O(n \log n)\)

集合拆分:将集合分为 \(W = \{1, 2, 3, \cdots, n\} \backslash S\)\(S\) 。讨论 \(retA\) 的选择对 \(retB\) 是否存在位影响。
考虑 \(retA\)\(S\) 有交集,或全在 \(W\) 中。

  1. \(retA\) 全在 \(W\) 中,\(retB\) 的数位贡献恒定。则 \(retA\) 一定等于 \(W\) 中最大的两数 \(gcd\)
    贡献证明:对于任意数位 \(d\) ,只需存在 \(0\) ,由于与 \(retA\) 无交, \(retB\) 的这一位恒是 \(0\) 。若全 \(1\) ,无论 \(retA\) 是否有交,\(retB\) 这一位恒是 \(0\)\(retB\) 的贡献恒不变,\(retB\) 恒不变。\(\square\)
    \(retB\) 恒定,考虑如何得到 \(retA\) 。朴素枚举两个数时间是 \(O(n^2)\) 的,如何加速?
    两个数的最大公约数最大,这是个典型问题
    \(1 \sim m\) 的因子个数是 \(O(n \log n)\) 的。一个朴素的证明是因子和倍数成对,\(1 \sim m\) 的倍数是调和级的。
    从大到小枚举约数 \(d \in [1, m]\) ,看它是否是两个数的公约数。最大的“公约数”就是“最大公约数”。用调和的复杂度求出 \(d\)\(a\) 中但不在 \(S\) 中的倍数个数 \(cnt\) ,若 \(cnt \geq 2\) ,则任意两个数是答案。
  2. 考虑 \(retA\)\(S\) 有交集,选择策略会影响 \(retB\) 的数位贡献。
    贡献证明: 这是显然的,\(retA\) 的选择可能导致 \(retB\) 在某些数位上得到更多的贡献。\(\square\)
    考虑 \(retA\) 如何求。朴素算法的合理性显然。第一个数在 \(S\) 中枚举,第二个数 \(O(n)\) 枚举,枚举复杂度为 \(O(n \log n)\) 。此时 check 下的 \(retA\)\(retB\) 可以被确定。check 的瓶颈在 \(retA\) 的 gcd 计算复杂度 \(\log n\)\(retB\) 的计算复杂度可以 ST 表预处理区间位和,并 \(O(1)\) 计算三段位和,只需 \(retA > retB\) 就是一个答案。时间复杂度 \(O(n \log^2 n)\)
posted @ 2024-03-30 21:49  zsxuan  阅读(13)  评论(0编辑  收藏  举报