题目描述

序列查询 - 图3 是一个由 n+1 个 [0,N) 范围内整数组成的序列,满足序列查询 - 图4(这个定义中蕴含了 n 一定小于 N。)
基于序列 A,对于 [0,N) 范围内任意的整数 x,
查询 序列查询 - 图5定义为:序列 A 中小于等于 x 的整数里最大的数的下标。具体来说有以下两种情况:

  1. 序列查询 - 图6

序列查询 - 图7
2.序列查询 - 图8
即是
序列查询 - 图9
序列查询 - 图10
序列查询 - 图11
对于给定的序列 A,试计算序列查询 - 图12

  1. v=list(map(int,input().split()))
  2. n,m=v[0],v[1]
  3. a =list(map(int,input().split()))
  4. sum =0
  5. for i in range(len(a)-1):
  6. if a[i]<m and a[i+1]>m:
  7. sum+=(m-a[i])*(i+1)
  8. break
  9. else:sum+=(a[i+1]-a[i])*(i+1)
  10. if m>a[-1]:
  11. sum+=(m-a[-1])*n
  12. print(sum)

首先定义了比例系数 序列查询 - 图13,其中 ⌊ ⌋ 表示下取整,即 r 等于 N 除以 n+1 的商。进一步地,用序列查询 - 图14表示自己估算出的 f(x) 的大小,这里同样使用了下取整来保证 g(x) 是一个整数。
显然,对于任意的询问 序列查询 - 图15 越接近则说明小 P 的估计越准确,后续进行线性查找的时间开销也越小。因此,小 P 用两者差的绝对值序列查询 - 图16来表示处理询问 x 时的误差。
为了整体评估小 P 同学提出的方法在序列 A 上的表现,试计算:
序列查询 - 图17

优化求和

想法:

不是从0遍历到序列查询 - 图18,而是遍历序列A的长度,即是序列查询 - 图19,需要

  • 把相同的序列查询 - 图20合并计算
  • 对绝对值进行拆开讨论
  • 合并计算序列查询 - 图21

    如何分开计算序列查询 - 图22

    对于序列查询 - 图23有相同的序列查询 - 图24

    但是如何计算序列查询 - 图25定义前缀和:

    序列查询 - 图26,假如我们可以很快地计算出序列查询 - 图27
    于是就可以在序列查询 - 图28分开计算序列查询 - 图29
    序列查询 - 图30
    序列查询 - 图31
    序列查询 - 图32:
    序列查询 - 图33
    当绝对值的变号发生在区间内部时,即是序列查询 - 图34
    序列查询 - 图35边界点是 序列查询 - 图36,
    序列查询 - 图37
    序列查询 - 图38
    进一步可以优化:只需要把判断移到内部,替换掉求和的边界以序列查询 - 图39
    1. for i in range(len(a)-1):
    2. x = r*i
    3. if (x>a[i]):
    4. real = min(a[i+1],x)
    5. sum += (real-a[i])*i-(h(real-1)-h(a[i]-1))
    6. if(x<a[i+1]):
    7. real =max(a[i],x)
    8. sum += h(a[i + 1] - 1) - h(real - 1) - (a[i + 1] - real) * i
    如何计算序列查询 - 图40?
    例子:取x=7,r=3
i 0 1 2 3 4 5 6 7
g(i) 0 0 0 1 1 1 2 2

可以看作有r个独立的等差数列{0,1},与余下不能分配到r个构成等差数列的数
等差数列,首项为0,末项为序列查询 - 图41,有序列查询 - 图42
剩下的数均为序列查询 - 图43,有序列查询 - 图44
序列查询 - 图45

  1. def h(x):
  2. t = (x+1)//r
  3. return r*(t-1)*t/2+t*((x+1)%r)

一一对应相

  1. v=list(map(int,input().split()))
  2. n,m=v[0],v[1]
  3. a =list(map(int,input().split()))
  4. max_num =a[-1]
  5. b=[0]*a[0]
  6. for index in range(n-1):
  7. b+=[index+1]*(a[index+1]-a[index])
  8. b+=[n]
  9. sum =0
  10. r = m//(n+1)
  11. if m>n:
  12. for i in range(max_num+1):
  13. sum+=abs(i//r-b[i])
  14. for j in range(max_num+1,m):
  15. sum+=abs(j//r-b[-1])
  16. else:
  17. for i in range(m):
  18. sum+=abs(i//r-b[i])
  19. print(sum)
  1. v=list(map(int,input().split()))
  2. n,m=v[0],v[1]
  3. a =list(map(int,input().split()))
  4. max_num =a[-1]
  5. b=[0]*a[0]
  6. for index in range(n-1):
  7. b+=[index+1]*(a[index+1]-a[index])
  8. b+=[n]
  9. sum =0
  10. r = m//(n+1)
  11. if m>n:
  12. for i in range(max_num+1):
  13. sum+=abs(i//r-b[i])
  14. for j in range(max_num+1,m):
  15. sum+=abs(j//r-b[-1])
  16. else:
  17. for i in range(m):
  18. sum+=abs(i//r-b[i])
  19. print(sum)