1 条题解

  • 0
    @ 2025-12-9 19:27:09

    问题分析

    我们有:

    • nn 个知识点(n6n \le 6
    • 每个知识点有 mm 道题(m666m \le 666
    • 每道题有 (ai,j,di,j)(a_{i,j}, d_{i,j}),表示算法和数据结构能力提升(可正可负)
    • 对每个学生 kk,必须从知识点 ii 选恰好 ck,ic_{k,i} 道题
    • 目标是最大化 A2+D2A^2 + D^2,其中:$$A = \sum_{i=1}^n \sum_{j \in S_i} a_{i,j}, \quad D = \sum_{i=1}^n \sum_{j \in S_i} d_{i,j} $$SiS_i 是第 ii 个知识点选出的题号集合,且 Si=ck,i|S_i| = c_{k,i}

    思路推导

    1. 最大化的几何意义

    A2+D2A^2 + D^2 是向量 (A,D)(A,D) 长度的平方。
    我们固定 A,DA,D 的取值范围,问题等价于:在所有可能的 (A,D)(A,D) 中,选离原点最远的点。


    2. 对每个知识点单独考虑

    对于知识点 ii,要从 mm 道题中选 cc 道题,所有可能的 (a,d)(a,d) 之和构成一个集合。
    这个集合可能很大,但是我们可以用背包 DP 求出来:
    fi(x,y)f_i(x,y) 表示从该知识点中选 cc 道题,能否得到 (Ai=x,Di=y)(A_i = x, D_i = y)
    由于 a,da,d 范围很大([109,109][-10^9,10^9]),直接枚举 x,yx,y 不现实。


    3. 关键观察:凸包优化

    我们要求的是 max(A2+D2)\max(A^2 + D^2),即最大化向量模长。
    对于给定的一个点集,模长最大的点一定在点集的凸包上(二维情况下显然,因为凸包外的点一定可以用凸包上的点“向外”推得更远)。

    因此,对于每个知识点 ii 和选 cc 道题的情况,我们先求出所有可能的 (Ai,Di)(A_i,D_i)凸包
    凸包上的点数是 O(m)O(m) 的,比总可能点数 O(m2值域)O(m^2 \cdot \text{值域}) 小得多。


    4. 如何求凸包

    对固定的 i,ci,c,我们先用二维背包 DP 枚举所有可能 (Ai,Di)(A_i,D_i),但只需要记录可达性,并找出所有可达的点。
    具体做法:

    • dp[t][x]dp[t][x] 表示选 tt 道题,得到的 Ai=xA_i = x 时,DiD_i 的所有可能值集合。
    • 由于 dd 值范围大,集合用 bitset 存储(bitset<最大值偏移>)。
    • 这样 O(nmcmaxA/w)O(n \cdot m \cdot c \cdot \text{maxA} / w),但 maxA\text{maxA} 太大?不能直接做。

    需要另一种方法:
    因为 m666m \le 666,选 cc 道题,可能的 (Ai,Di)(A_i,D_i) 点数最多 C(m,c)C(m,c) 种,仍然很大,但凸包点数是 O(m)O(m)

    一个更聪明的做法:
    所有可能的点直接求凸包不可行(点太多),我们改为用DP 生成凸包

    • 对于每个知识点 ii,对每个 cc,直接枚举所有 mmcc 的组合,计算 (Ai,Di)(A_i,D_i),存下这些点,然后求凸包。
      枚举 C(m,c)C(m,c) 复杂度太高(m=666,c=333m=666, c=333 太大)。
    • n6n \le 6m666m \le 666,我们不需要对每个 cc 都求,而是对于每个 ii,我们只需对 0cm0 \le c \le m 这些 cc 值,分别求出选 cc 道题时的凸包点集。
      这里可以用Meet-in-the-middle(折半搜索):
      • mm 道题分成两半(各约 m/2m/2
      • 分别枚举两半的所有子集(2m/223332^{m/2} \approx 2^{333} 仍然太大,不行)

    所以必须用背包 DP + 凸包合并


    5. 凸包合并

    如果我们已经知道知识点 iicc 道题的所有可能点集 Pi,cP_{i,c}(只保留凸包点),那么对于学生 kk,需要选 ck,ic_{k,i} 道题从每个 ii,我们要求:

    $$(A,D) = \sum_{i=1}^n (A_i,D_i), \quad (A_i,D_i) \in P_{i, c_{k,i}} $$

    的最大 A2+D2A^2 + D^2

    这相当于 nn 个凸包的和(Minkowski 和)的最大模长点。


    6. Minkowski 和的性质

    两个凸包 C1,C2C_1, C_2 的 Minkowski 和 C1+C2C_1 + C_2 的凸包,是它们各自凸包的 Minkowski 和,且新凸包的顶点由 C1C_1C2C_2 的顶点按极角排序后依次相加得到。

    因此我们可以:

    1. 对每个 Pi,cP_{i,c} 求凸包,按极角排序。
    2. 依次合并凸包(nn 很小,所以合并 nn 次可以接受)。
    3. 在最终凸包上找离原点最远的点(即最大 A2+D2A^2 + D^2)。

    7. 求每个 Pi,cP_{i,c} 的凸包

    这里需要高效求出 Pi,cP_{i,c}
    DP 记录所有可达的 (Ai,Di)(A_i,D_i) 仍然困难(值域大)。
    m666m \le 666,我们可以用费用流思想
    不,这是子集选取问题,可以用折半枚举 + 双指针求凸包

    • mm 道题分成两半 LLRR(各 333\le 333
    • 枚举 LL 中选 tt 道题的所有子集,计算 (AL,DL)(A_L, D_L),存到数组 left[t]left[t]
    • 枚举 RR 中选 ctc-t 道题的所有子集,计算 (AR,DR)(A_R, D_R),存到数组 right[ct]right[c-t]
    • 对所有 tt,将 left[t]left[t]right[ct]right[c-t] 中的点两两相加,得到总点集,再求凸包。

    left[t]left[t] 的大小是 C(L,t)C(|L|,t),仍然可能很大(t166t \approx 166 时很大)。
    不过 n6n \le 6,总合并次数不多,且 cc 随机均匀,所以实际组合数不会达到最大,可能可行。

    但更稳妥的做法:用 DP 存储所有 (Ai,Di)(A_i,D_i) 的凸包而不是所有点。


    8. 凸包 DP 设计

    对于固定的知识点 ii,我们定义 dpcdp_c 为选 cc 道题的所有 (Ai,Di)(A_i,D_i) 的凸包(点集)。
    初始 dp0={(0,0)}dp_0 = \{(0,0)\}
    转移:加入一道题 (a,d)(a,d)

    $$dp_{c}' = \text{ConvexHull}(dp_{c} \cup \{ p + (a,d) \mid p \in dp_{c-1} \}) $$

    这个凸包合并可以用 Minkowski 和求凸包的方法。

    但直接做复杂度:O(m凸包大小2)O(m \cdot \text{凸包大小}^2) 可能较大,但凸包大小 O(m)O(m),所以 O(m3)O(m^3),对于 m=666m=666 太大。


    9. 利用值随机性质

    题目提示 ck,ic_{k,i} 随机均匀生成,所以 cc 不会极端靠近 00mm,平均 m/2\approx m/2
    但我们仍需要可靠算法。

    考虑折半枚举 + 凸包合并: 对每个 iicc,我们真的需要枚举所有组合吗?
    我们可以枚举左半部分选 tt 道的所有可能 (AL,DL)(A_L,D_L),求其凸包 HL[t]H_L[t];右半部分选 ctc-t 道的凸包 HR[ct]H_R[c-t]
    然后 HL[t]+HR[ct]H_L[t] + H_R[c-t] 的凸包就是这两个凸包的 Minkowski 和。
    再对所有 tt 的结果取凸包并集,得到 Pi,cP_{i,c}

    这样 HL[t]H_L[t] 的大小是 O(L)O(|L|)HR[ct]H_R[c-t] 大小 O(R)O(|R|),Minkowski 和求凸包 O(HL+HR)O(|H_L| + |H_R|),总复杂度 O(m2)O(m^2) 对每个 (i,c)(i,c),可以接受。


    10. 最终步骤

    1. 预处理:
      • 对每个知识点 ii,对每个 c[0,m]c \in [0, m],用折半法求 Pi,cP_{i,c}(凸包点集,按极角排序)。
    2. 回答询问:
      • 对于学生 kk,取 Qi=Pi,ck,iQ_i = P_{i, c_{k,i}}
      • 用 Minkowski 和依次合并 Q1,Q2,,QnQ_1, Q_2, \dots, Q_n,得到总凸包 TT
      • TT 上找 A2+D2A^2 + D^2 最大的点。
      • 因为 TT 是凸多边形,最大模长点一定在凸包顶点上,直接枚举顶点即可。

    复杂度分析

    • 预处理:n(m+1)O(m2)O(nm3)n \cdot (m+1) \cdot O(m^2) \approx O(n m^3)n6,m666n \le 6, m \le 666,勉强可过。
    • 询问:$q \cdot n \cdot (\text{凸包大小}) \le 666 \cdot 6 \cdot O(m) \approx 2.6 \times 10^6$,可以。

    实现细节

    1. __int128BigIntegerA2+D2A^2 + D^2,避免溢出。
    2. 凸包算法用 Andrew 单调链 O(plogp)O(p \log p)
    3. Minkowski 和:两个凸包 P,QP,Q 已按极角排序,则 P+QP+Q 的凸包可通过归并得到。
    4. 注意去重和边界情况。

    总结

    本题的核心在于:

    1. 将最大化 A2+D2A^2 + D^2 转化为在凸包上找最远点。
    2. 对每个知识点、每个选题数量求凸包,用折半枚举 + Minkowski 和高效计算。
    3. 合并各知识点的凸包得到总凸包,求最大模长。

    利用凸包性质和 Minkowski 和,将看似 O(2m)O(2^m) 的枚举问题降为 O(m3)O(m^3) 的可解问题。

    • 1

    「THUPC 2018」《算法与数据结构》小助教招募通知 / Dsa

    信息

    ID
    5953
    时间
    1500ms
    内存
    2048MiB
    难度
    10
    标签
    递交数
    5
    已通过
    1
    上传者