全部评论 1

  • 好的,我将为你提供一份完整的 AC(Accepted)代码,使用前缀和优化方法高效求解每个区间的和,并详细解释你提供代码中的错误。

    问题概述

    题目要求给定长度为 n (≤10^5) 的数组和 m (≤10^5) 个区间查询,每个查询给出 [a,b],需要输出该区间内所有元素之和。

    原代码错误分析

    原代码存在多处问题:

    • 数组大小不足导致越界:题目中 n,m 最大可达 10^5,而代码中各数组(如 iay1_1iay1_2iay1_3iay1_4)的长度仅为 10005,一旦 n 或 m 超过此值,就会发生数组越界。
    • 循环边界错误:对查询求和时,代码写为 for(int j=iay1_2[i]-1; j<iay1_3[i]-1; j++),这实际只累加到索引 b-2,未包含区间右端点 b-1 的元素,导致求和结果偏小。正确的循环条件应为 j <= iay1_3[i]-1 或者简化为 j < iay1_3[i] 才能包含端点。
    • 输出次数错误:题目要求对每个查询输出一个结果,总共输出 m 个整数;而原代码输出循环是 for(int i=0;i<r1;i++),却输出了 r1(即 n)个结果,显然与查询数目 m 不符。正确做法应输出 m 行答案。
    • 时间复杂度过高:即使修正上述错误,原代码对每个查询使用嵌套循环累加,最坏情况时间复杂度为 O(n·m),当 n,m≈10^5 时会达到 10^10 级别运算,很难在 1 秒内完成。实际中需要使用 前缀和 等技巧将每次查询的时间降为 O(1),以大幅降低查询时间复杂度。

    完整 AC 代码(前缀和方法)

    下面给出基于前缀和的正确解法:先预处理出数组的前缀和 prefix[i] = A[1]+...+A[i],然后每个查询 [l,r] 的和为 prefix[r] - prefix[l-1]

    #include <iostream>
    using namespace std;
    
    const int MAXN = 100000 + 5;
    long long prefix[MAXN];  // 前缀和数组
    
    int main() {
        int n, m;
        cin >> n >> m;
        prefix[0] = 0;
        // 读入数组并构造前缀和
        for (int i = 1; i <= n; i++) {
            long long x;
            cin >> x;
            prefix[i] = prefix[i-1] + x;
        }
        // 处理每个查询
        while (m--) {
            int l, r;
            cin >> l >> r;              // 查询区间 [l,r]
            cout << (prefix[r] - prefix[l-1]) << endl;
        }
        return 0;
    }
    

    错误原因总结

    1. 输出条数和索引错误:原代码最后的输出循环使用了 i<r1,而正确应输出 m 个查询结果。原题说明“对于 m 个询问,每个询问输出一个整数”。此外,求和时循环条件也写错了,导致未包含右端点。
    2. 数组越界:原代码中静态数组长度仅为 10005,但题目 n、m 最多为 10^5,存在越界风险。
    3. 效率问题:暴力双重循环累计会导致超时。应采用前缀和等预处理手段使得每次查询均在 O(1) 时间内完成,从而“能大大降低查询的时间复杂度”。

    上述修改后的代码修正了所有索引和边界问题,并通过前缀和使查询高效,可在题目给定的规模下 AC。

    参考资料: 题目描述,前缀和算法介绍

    2025-07-07 来自 浙江

    0

热门讨论