Algorithm 如何以最佳时间复杂度高效地解决此问题?

Algorithm 如何以最佳时间复杂度高效地解决此问题?,algorithm,performance,logic,Algorithm,Performance,Logic,在一个数组中给定一组N个数。给定Q查询。每个查询包含1个数字x 对于每个查询,需要向数组的每个元素添加x,然后报告数组中绝对值的总和 注意:对数组的更改是永久性的。有关更多说明,请参见示例 输入格式 第一行包含N,数组中的元素数。 下一行包含数组的N个空格分隔整数。 下一行包含Q(查询数)。 下一行包含Q空间分隔的整数(数字x) 输出格式 对于每个查询,以换行形式输出总和 约束条件 1.≤ N≤ 500000 1.≤ Q≤ 500000 -2000 ≤ 每个查询中的数字≤ 2000年 -2000

在一个数组中给定一组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
3
1-2 3

样本输出

5
7
6
5
7
六,

解释

在查询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;

  } 

}  
#包括
#包括
int main()
{
整数n,*a,q,*aq;
长整数和=0;
scanf(“%d”和“&n”);
a=(int*)malloc(sizeof(int)*n);

对于(inti=0;i,您的解决方案正在执行N.Q操作,这是非常巨大的

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

然后将请求的总和作为每个bin的绝对差值之和,通过bin值进行加权。这将工作负载从N.Q降低到B.Q(B是bin的数量)



如果我是对的,我们可以通过将总和分解为负值和正值来做得更好。这些总和是通过计算前缀和得到的。这将导致在对B操作中的直方图进行预处理后,在Q操作中得到一个解决方案。

以下是一个算法的概要:

样本输入

3
-1 2 -3
对数据进行排序并计算前缀和:

-3, -1, 2
-3, -4, -2 (prefix sums)
(使用直方图作为Yves Daoust将消除初始排序和任何二进制搜索以查找以下三个部分,这将显著优化复杂性。)

保持运行增量:

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
* 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
* 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
查询-2:

* 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
* 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
* 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
查询3:

* 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
* 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
* 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

对于每个查询,数组中的数字可能分别为负数、换号和正数。如果您不遵循Yves Daoust(狡猾)的建议对输入值进行bin(排序,在该词的一种解释中)排序,请考虑对它们进行排序(排序的另一种含义)。保留一个值偏移量以供每个查询修改(不更新数组项)和第一个非负项的索引。对于每个查询,后者将是“感兴趣的项”范围的一端-搜索另一端的
-x
(由偏移量修改)。