序列查询新解(python满分解法)

一、问题描述

试题编号: 202112-2
试题名称: 序列查询新解
时间限制: 1.0s
内存限制: 512.0MB
问题描述:
题目背景
上一题“序列查询”中说道:
是一个由 个 范围内整数组成的序列,满足
。基于序列 ,对于 范围内任意的整数 ,查询 定义为:序列 中小于等于 的整数里最大的数的下标。

对于给定的序列 和整数 ,查询 是一个很经典的问题,可以使用二分搜索在 的时间复杂度内轻松解决。但在 IT 部门讨论如何实现这一功能时,小 P 同学提出了些新的想法。

题目描述
小 P 同学认为,如果事先知道了序列 中整数的分布情况,就能直接估计出其中小于等于 的最大整数的大致位置。接着从这一估计位置开始线性查找,锁定 。如果估计得足够准确,线性查找的时间开销可能比二分查找算法更小。

比如说,如果
均匀分布在 的区间,那么就可以估算出:

为了方便计算,小 P 首先定义了比例系数

,其中 表示下取整,即 等于 除以 的商。进一步地,小 P 用

表示自己估算出的 的大小,这里同样使用了下取整来保证 是一个整数。

显然,对于任意的询问 , 和 越接近则说明小 P 的估计越准确,后续进行线性查找的时间开销也越小。因此,小 P 用两者差的绝对值 来表示处理询问 时的误差。

为了整体评估小 P 同学提出的方法在序列 上的表现,试计算:

输入格式
从标准输入读入数据。

输入的第一行包含空格分隔的两个正整数 和 。

输入的第二行包含 个用空格分隔的整数

注意
固定为 ,因此输入数据中不包括

输出格式
输出到标准输出。

仅输出一个整数,表示 的值。

样例1输入

3 10
2 5 8

Data
样例1输出

5

Data
样例1解释
在这里插入图片描述

样例2输入

9 10
1 2 3 4 5 6 7 8 9

Data
样例2输出

0

Data
样例3输入

2 10
1 3

Data
样例3输出

6

Data
样例3解释
在这里插入图片描述

二、python代码与注释

思路可以看参考文献。


n, N = tuple(map(int, input().split()))
# 有用的点
A = [0] + [int(x) for x in input().split()]


# 计算gi数列下标到x的和
def h(x):
    if x <= 0:
        return 0
    global r
    x = x+1
    n = x//r
    m = x%r
    return int(n*(r*(n-1)/2+m))


# 对下标为left到right的abs(fi-gi)求和,包括left和right两点
def cal(fi, left, right):
    return abs(h(right)-h(left-1)-fi*(right-left+1))


# 判断是否有转折点,并返回error增加量
def ischange(fi, left, right):
    # 没有转折点
    if left//r >= fi or right//r <= fi:
        return cal(fi, left, right);
    # 出现转折点
    else:
        # 算出第一个转折点
        splitindex = left + r*(fi-(left+1)//r)+r-(left+1)%r
        return cal(fi, left, splitindex)+ischange(fi, splitindex+1, right)


r = N//(n+1)
error = 0

# 根据fi的数值来分组,开始遍历
for fi in range(n+1):
    left = A[fi]
    if fi < n:
        right = A[fi+1]-1
    else:
        right = N-1
    error += ischange(fi, left, right)

print(error)

总结

  对于数据有规律的题目来说,一般要利用其规律,而不能直接一个个求解。(要利用数列求和的公式等)
  求差分的时候可以转化成两个前缀和函数的差(若前缀和函数好求的话)
  写代码时要注意区分好变量意义,是下标还是数量(特别是在计算其他下标位置时)

参考文献

序列查询新解cpp解析
ccfcsp官网题目

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值