【问题标题】:Competitive programming: "Time exceeded error"竞争性编程:“超时错误”
【发布时间】:2019-04-25 05:32:16
【问题描述】:

问题描述:

任务 A. 减法数量

你有一个数组 a 长度 n。有 m 个查询 (li,ri),对于每一个都是必要的 找到数字子数组的总和 [li,ri]

输入数据格式:

第一行包含两个整数nm (1 ⩽ n, m ⩽ 105) - 数字和查询的数量。第二 行包含 n 个整数 a1, a2,。 . . , an (1 ⩽ ai ⩽ 109) - 的个数 数组。以下 m 行中的每一行包含两个整数 liri (1 ⩽ li ⩽ ri ⩽ n) - 查询。

输出数据格式:

对于每个请求,请单独使用一行来回答它。

我的解决方案:

#include <stdio.h>

int main(void) {
    long n = 0;
    long m = 0;

    long l = 0;
    long r = 0;

    register long t = 0; // temporary variable, that contains intermediate results

    scanf("%ld%ld", &n, &m);

    long  a[n];
    long  tr[m]; // array, that contains results

    for (register long i = 0; i < n; i++)
        scanf("%ld", &a[i]);

    for (register long i = 0; i < m; i++) {
        scanf("%ld%ld", &l, &r);

        l--;
        r--;

        t = 0;
        if (l != r) {
            for (register long j = l; j <= r; j++)
                t += *(a + j);
        } else t = *(a + l);

        tr[i] = t; 
    }
    for (register long i = 0; i < m; i++)
        printf("%ld\n", tr[i]);


    return 0;
}

我的解决方案是 11 次测试中只有 6 次通过。其他 5 次总是返回

超时错误

我对竞争性编程真的很陌生。 我应该如何优化我的代码以使 big-O 复杂度低于 O(n2)? 任何帮助将不胜感激。 p>

【问题讨论】:

  • 我对竞争性编程真的很陌生。 -- long a[n]; -- 这不是有效的 C++。 C++ 中数组中的条目数由编译时常量表示,而不是变量。不幸的是,“竞争性编程”并没有教你如何编写程序。
  • @PaulMcKenzie,它不是 C++。该程序是用 C 语言编写并使用 GCC 编译的。没有警告或错误。
  • 你以前有 C++ 标签。无论如何,您的解决方案是O(n^2)。你有一个嵌套循环——想象一下m 是否非常大。这可能是超时的原因。任何使用嵌套循环的解决方案通常都不会通过这些测试,因为这些测试旨在让您编写“简单”但太慢的幼稚解决方案。你必须设计一个大O复杂度小于n^2的解决方案
  • @PaulMcKenzie 我删除了 c++ 标签,因为它看起来不相关。您可以使用该表达式(在 C 和 C++ 中),它可以在 gcc 或 clang 中使用。但我认为这是 gcc 编译器的一个特性,按标准是非法的。
  • @Afshin,不,这不是编译器的功能,具有可变条目数的数组表现为 VLA。

标签: c gcc optimization


【解决方案1】:

计算数组的累计和,存入另一个,也就是说, accumulated[i] = 到第 i 个索引的数组数字的总和。这可以在 O(n) 中计算出来。

那么对于查询,答案将是accumulated[r] - accumulated[l]。这是 O(1)

【讨论】:

    【解决方案2】:

    这个问题可以在O(n)时间复杂度和O(n)空间复杂度上解决。

    您可以使用前缀和方法来降低复杂性。假设一个长度为 4 的数组包含元素 a0、a1、a2、a3,创建一个单独的数组,其中包含索引 i 的 i 个元素的总和。

    原始数组 arr[]: a0, a1, a2, a3
    前缀和数组 p[]: a0, a0+a1, a0+a1+a2, a0+a1+a2+a3

    对于“a1 和 a2”之和:a1+a2 = p[2] - p[0]

    对于'a1 and a2 and a3'之和:a1+a2+a3 = p[3] - p[0]
    对于 'a2 和 a3' 的总和:a2+a3 = p[3] - p[1]

    以上行表明,对于从 'L 到 R' 的元素之和,我们必须打印 p[R] - p[L-1]

    注意:对于 L=0,我们必须打印 p[R] 因为它是直到 R 的所有元素的总和,并且没有索引为'-1'的元素。

    创建前缀和数组的代码:

    如果我们有一个包含“long int”数据类型并命名为 arr、大小为 n 的数组,那么:

    long p[n];
    p[0] = arr[0];
    for(long i=1;i<n;i++)
    {
        p[i] = p[i-1] + arr[i];
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-02-15
      • 1970-01-01
      • 2023-03-08
      • 1970-01-01
      • 2021-01-07
      • 2022-01-16
      • 2018-09-15
      相关资源
      最近更新 更多