1 条题解

  • 0
    @ 2025-10-28 16:16:48

    题意理解

    • nn 个城堡,ss 个对手,小 C 有 mm 个士兵。
    • 每个对手在每个城堡 ii 上派兵 ak,ia_{k,i}(已知)。
    • 小 C 要确定一个固定的派兵方案 (x1,x2,,xn)(x_1, x_2, \dots, x_n),满足 xim\sum x_i \le m,用于与 ss 个对手分别对战。
    • 对战规则:
      对于城堡 ii,如果小 C 的士兵数 xi>2×ak,ix_i > 2 \times a_{k,i},则小 C 在该城堡战胜对手 kk,得到 ii 分(注意:得分是城堡编号 ii,不是士兵数)。
    • 与一个对手对战的总分 = 所有战胜的城堡编号之和。
    • 最终小 C 的总分 = 与 ss 个对手对战得分的总和。
    • 求最大总分。

    关键点分析

    1. 固定方案:小 C 的方案对所有 ss 个对手是一样的。
    2. 得分规则:在城堡 ii 上,战胜对手 kk 的条件是 xi>2ak,ix_i > 2a_{k,i},战胜后得分 ii(注意是城堡编号)。
    3. 目标:最大化 ss 场对战的总得分。

    思路推导

    对单个城堡 ii 的分析

    假设在城堡 ii 上,小 C 派兵 tt

    对手 kk 在该城堡派兵 ak,ia_{k,i}
    如果 t>2ak,it > 2a_{k,i},则小 C 在这场对战中得到 ii 分。

    因此,对于固定的 tt,我们可以知道哪些对手会在这个城堡上被战胜。


    转化为背包问题

    我们可以按城堡来规划,把 mm 个士兵分配到 nn 个城堡。

    f[j]f[j] 表示使用 jj 个士兵时能获得的最大总分。

    对于城堡 ii,如果我们派兵 tt,则:

    • 成本 = tt 个士兵
    • 收益 = 在城堡 ii 上战胜的对手数量 ×i\times i(因为每个战胜的对手得 ii 分)

    计算收益

    对于城堡 ii,我们考虑所有 ss 个对手,按 ak,ia_{k,i} 升序排序。

    假设排序后为 b1b2bsb_1 \le b_2 \le \dots \le b_s

    如果我们派兵 tt,那么 t>2bjt > 2b_jjj 都会输给我们。
    也就是说,如果 t>2bpt > 2b_p,则战胜前 pp 个对手(因为排序后前面的对手派兵更少,更容易战胜)。

    因此,派兵 tt 时,战胜的对手数量 = 最大的 pp 满足 t>2bpt > 2b_p

    那么收益 = p×ip \times i


    枚举与状态转移

    对每个城堡 ii,我们枚举派兵 tt0tm0 \le t \le m),计算收益 vi,t=p×iv_{i,t} = p \times i,其中 pp 如上计算。

    然后做分组背包:每个城堡是一组,每组只能选一个派兵方案(一个 tt),总士兵数不超过 mm

    转移方程:

    f[j]=max(f[j],  f[jt]+vi,t)f[j] = \max(f[j],\; f[j-t] + v_{i,t})

    其中 jjmmtt 倒序枚举(01背包)。


    算法步骤

    1. 读入 s,n,ms, n, m
    2. 读入 s×ns \times n 的矩阵 aa
    3. 对每个城堡 ii,收集所有对手在该城堡的派兵 ak,ia_{k,i},排序。
    4. 计算 vi,tv_{i,t}:对 t=0mt = 0 \dots m,找出最大的 pp 满足 t>2bpt > 2b_p,收益 =p×i= p \times i
    5. 分组背包 DP:f[0m]f[0 \dots m] 初始 0,对每个城堡 ii,对每个 ttmmtt 更新 f[j]f[j]
    6. 输出 max(f[0m])\max(f[0 \dots m])

    复杂度

    • 计算 vi,tv_{i,t}O(n(m+slogs))O(n \cdot (m + s \log s))
    • 分组背包:O(nm(m?))O(n \cdot m \cdot (m?)) 不对,这里 tt 最多 mm,所以是 O(nm2)O(n \cdot m^2)
      但注意 tt 枚举到 mm,但 mm 最大 2×1042\times 10^4n=100n=100,那么 nm2n m^2 会到 4×10104\times 10^{10},不可行。

    优化

    实际上,tt 不需要从 00mm 全部枚举,因为收益 vi,tv_{i,t} 只在 tt 超过某个 2bp+12b_p+1 时变化。
    所以 tt 的取值只有 O(s)O(s) 个关键点:t=2bp+1t = 2b_p + 1 以及 t=0t=0

    这样,每个城堡我们只需枚举 O(s)O(s)tt,总复杂度 O(nsm)O(n \cdot s \cdot m)n100,s100,m20000n \le 100, s \le 100, m \le 20000,最大 2×1082\times 10^8,勉强可过(优化常数)。


    示例代码(C++)

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    
    int main() {
        int s, n, m;
        cin >> s >> n >> m;
        
        vector<vector<int>> a(s, vector<int>(n));
        for (int i = 0; i < s; i++) {
            for (int j = 0; j < n; j++) {
                cin >> a[i][j];
            }
        }
        
        vector<int> f(m + 1, 0);
        
        for (int i = 0; i < n; i++) {
            // 对城堡 i,收集所有对手的兵力
            vector<int> b;
            for (int k = 0; k < s; k++) {
                b.push_back(a[k][i]);
            }
            sort(b.begin(), b.end());
            
            // 计算收益函数
            vector<int> profit(m + 1, 0);
            for (int t = 1; t <= m; t++) {
                int cnt = 0;
                for (int k = 0; k < s; k++) {
                    if (t > 2 * b[k]) {
                        cnt++;
                    } else {
                        break; // 因为排序了,后面不可能满足
                    }
                }
                profit[t] = cnt * (i + 1); // 城堡编号从1开始
            }
            
            // 分组背包
            for (int j = m; j >= 0; j--) {
                for (int t = 1; t <= m; t++) {
                    if (j >= t) {
                        f[j] = max(f[j], f[j - t] + profit[t]);
                    }
                }
            }
        }
        
        int ans = 0;
        for (int j = 0; j <= m; j++) {
            ans = max(ans, f[j]);
        }
        cout << ans << endl;
        
        return 0;
    }
    

    样例验证

    样例 1

    1 3 10
    2 2 6
    

    输出 3,符合。

    样例 2

    2 3 10
    2 2 6
    0 0 0
    

    输出 8,符合。


    总结

    这道题的核心是:

    1. 将问题按城堡分解,计算在每个城堡上派兵 tt 时的收益(战胜的对手数 × 城堡编号)。
    2. 使用分组背包模型,在总士兵数限制下分配兵力,最大化总分。
    3. 利用排序和阈值优化,减少枚举量。
    • 1

    信息

    ID
    4517
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者