如何以最佳的时间复杂度以有效的方式解决此问题?

时间:2018-12-20 20:13:18

标签: algorithm performance logic

给出数组中的一组N个数字。给定Q查询。每个查询包含1个数字x。

对于每个查询,您需要将x添加到数组的每个元素,然后报告数组中的绝对值之和。

注意:对数组的更改是永久的。请参阅示例以获取更多说明。

输入格式

第一行包含N,即数组中元素的数量。 下一行包含N个以空格分隔的整数数组。 下一行包含Q(查​​询数量)。 下一行包含Q个空格分隔的整数(数字x)。

输出格式

对于每个查询,在换行符中输出总和。

约束
1≤N≤500000
1≤Q≤500000
-2000≤每个查询中的数字≤2000
-2000≤数组元素的值≤2000

样本输入

3
-1 2 -3
3
1 -2 3

样本输出

5
7
6

说明

查询1之后:[0,3,-2] => sum = 0 + 3 + 2 = 5

查询2之后:[-2,1,-4] => sum = 2 +1 + 4 = 7

查询3之后:[1,4,-1] => sum = 1 + 4 + 1 = 6

#include<stdio.h>
#include<stdlib.h>

int main()
{
  int n,*a,q,*aq;
  long int sum=0;
  scanf("%d",&n);
  a=(int*)malloc(sizeof(int)*n);
  for(int i=0;i<n;i++)
    scanf("%d",&a[i]);

  scanf("%d",&q);
  aq=(int*)malloc(sizeof(int)*q);
  for(int i=0;i<n;i++)
    scanf("%d",&aq[i]);

  for(int i=0;i<q;i++)
  {
    for(int j=0;j<n;j++)
    {
        sum+=abs(aq[i]+a[j]);
        a[j]=aq[i]+a[j];
    }

    printf("%ld\n",sum);
    sum=0;

  } 

}  

一些测试用例正在超时。

2 个答案:

答案 0 :(得分:2)

您的解决方案正在执行大量的N.Q操作。

首先请注意,数据范围适中,因此您可以使用4001个条目的直方图表示N个数字。此直方图是通过N次操作(加上初始化bin)计算出来的。

然后,将获得的请求总和作为每个bin的绝对差之和,并用bin值加权。这样可以将工作量从N.Q减少到B.Q(B是箱数)。


如果我是对的,我们可以通过分解一个负值和一个正值的总和来做得更好。并且这些和是通过计算前缀和而获得的。在对B运算中的直方图进行预处理之后,这应该会导致Q运算中的解决方案。

答案 1 :(得分:0)

以下是算法的概述:

样本输入

3
-1 2 -3

对数据进行排序并计算前缀总和:

-3, -1, 2
-3, -4, -2 (prefix sums)

(使用直方图作为Yves Daoust suggested可以消除初始排序和任何二进制搜索,从而找到下面的三个部分,这将极大地优化复杂性。)

维护运行中的增量:

delta = 0

对于每个查询

1 -2 3

查询1:

* update delta:
  delta = 0 + 1 = 1

* identify three sections:
  [negative unaffected] [switches sign] [positive unaffected]
       -3,   -1,                                 2

* Add for each section abs(num_elements * delta + prefix_sum):
   abs(2 * 1 + (-4 - 0))        +        abs(1 * 1 + (-2 -(-4)))
   = abs(2 - 4) + abs(1 + 2)
   = 5

查询-2:

* update delta:
  delta = 1 - 2 = -1

* identify three sections:
  [negative unaffected] [switches sign] [positive unaffected]
       -3,   -1,                                 2

* Add for each section abs(num_elements * delta + prefix_sum):
   abs(2 * (-1) + (-4 - 0))     +     abs(1 * (-1) + (-2 -(-4)))
   = abs(-2 - 4) + abs(-1 + 2)
   = 7

查询3:

* update delta:
  delta = -1 + 3 = 2

* identify three sections:
  [negative unaffected] [switches sign] [positive unaffected]
       -3,                   -1,                   2

* Add for each section abs(num_elements * delta + prefix_sum):
 abs(1 * 2 + (-3 - 0)) + abs(1 * 2 + (-4 - (-3))) + abs(1 * 2 + (-2 -(-4)))
   = abs(2 - 3) + abs(2 - 1) + abs(2 + 2)
   = 6

样本输出

5
7
6