top1编程
← 返回题目
题解

最要强的飞行员

1 条题解

  • 0
    @ 2026-8-5 23:50:20

    P4761 最要强的飞行员(入门)

    解题思路

    故事里有 n 个据点,每个据点都有牢固值;m 轮攻击会各自攻打一段连续的据点,飞行员想挑"总牢固值最大"的那一轮去出战。所以这道题就是:给 m 个区间,分别求出每个区间的和,再找出其中的最大值。

    如果每轮攻击都用循环从头把区间里的数字加一遍,假设 n 和 m 都很大,会非常慢。我们用前缀和来加速:先算出 pre[i] 表示前 i 个据点的牢固值之和。那么第 L 到第 R 个据点的总牢固值就是 pre[R] - pre[L-1],一次减法就出结果,复杂度从 O(区间长度) 变成了 O(1)。

    接下来很简单:读入 m 轮的范围,每轮算出一个区间和 s,用一个变量 ans 记录目前最大的那个。如果 s 比 ans 大,就把 ans 更新成 s。所有轮次处理完之后,ans 就是答案。

    用样例验证:n=7,牢固值 2 10 5 3 6 4 9。第 1 轮打 3~5,和是 5+3+6=14;第 2 轮打 6~7,和是 4+9=13。两轮里最大的是 14,正好是输出。

    边界情况要想到:ans 一开始可以设成 -1,因为牢固值都是正整数,第一轮算出来的和一定比 -1 大,这样 ans 一定会被正确更新。另外 n 和 m 最大都是 500000,数组开到 500005,用 long long 存前缀和,防止数字相加溢出。

    参考代码

    // 求 m 轮攻击中总牢固值的最大值:先用前缀和求出每轮范围的和,再取最大
    #include <iostream>
    int main() {
        int n, m;
        std::cin >> n >> m;
        long long pre[500005] = {0}; // pre[i] 表示前 i 个据点的牢固值之和
        for (int i = 1; i <= n; ++i) {
            long long x;
            std::cin >> x;
            pre[i] = pre[i - 1] + x;
        }
        long long ans = -1; // 记录最大的总牢固值
        for (int i = 0; i < m; ++i) {
            int L, R;
            std::cin >> L >> R;
            long long s = pre[R] - pre[L - 1]; // 区间 L~R 的和
            if (s > ans) ans = s;
        }
        std::cout << ans << '\n';
        return 0;
    }
    

    复杂度分析

    建前缀和数组要 O(n) 时间,处理 m 个区间每个 O(1),所以总时间复杂度是 O(n+m)。空间上多开一个 pre 数组,是 O(n)。n 和 m 都最大 500000,加起来大约 100 万次操作,运行非常快,用最普通的枚举法(每个区间从头加)最坏会到 O(n*m)=2500 亿次,根本比不了,这就是前缀和的威力。

    • 1