洛谷 官方题库 第十天 Python

【算法2-1】前缀和、差分与离散化

一个长度为 n 的数组 a[0] a[n-1] ,它的前缀和 sum[i] 等于 a[0] a[i] 的和。
利用递推,只需 n 次就能计算出所有的前缀和: sum[i] = sum[i−1] + a[i]
也能用 sum[] 反推计算出 a[] a[i] = sum[i]−sum[i−1]
快速计算出数组中任意一个区间 a[i] a[j] 的和: a[i] + a[i+1] + ... + a[j−1] + a[j] = sum[j]−
sum[i−1]

一维前缀和

def Sn(a, n):
    s = [0] * (n + 1)  # 初始化 s 数组
    s[1] = a[0]
    for i in range(2, n + 1):
        s[i] = s[i - 1] + a[i - 1]
    return s

差分数组

diff[i]    =    A[i]                 i=1

                  A[i]−A[i−1]​       i≥2​

  • 如果对区间 [ l , r ] 进行修改,只需修改 d i f f [ l ] , d i f f [ r + 1 ] (diff[l]加上修改值,diff[r+1] 减去修改值)
  •  前缀和主要适用的场景是原始数组不会被修改的情况下,适用于快速、频繁地计算一个索引区间内的元素之和以及频繁查询某个区间的累加;差分数组的主要适用场景是频繁对原始数组的某个区间的元素进行增减。

 差分

根据差分数组的定义: d[i]=a[i]-a[i-1],可以发现,在d[x]上加上z,会让后面的学生全部加上z。↓(理解)

但这是把后面全部都加了,还要减掉一节,所以↓

把两个综合起来就是↓

 

所以每一次变化只要把d[x]+z,d[y+1]-z就好了。

因为 d[i]=a[i]-a[i-1]

所以 a[i-1]+d[i]=a[i]

python好像可以处理足够大的数,不用离散化?

 

P8218 【深进1.例1】求区间和

def Sn(a, n):
    s = [0] * (n + 1)  # 初始化 s 数组
    s[1] = a[0]
    for i in range(2, n + 1):
        s[i] = s[i - 1] + a[i - 1]
    return s

n = int(input())
a = list(map(int, input().split()))
m = int(input())

s = Sn(a, n)  # 计算 s 数组

for i in range(m):
    l, r = map(int, input().split())
    rel = s[r] - s[l - 1]
    print(rel)

P2367 语文成绩

def diff(a,n):
    d=[0]*(n)
    d[0]=a[0]
    for i in range(1,n):
        d[i]=a[i]-a[i-1]
    return d
n,p=map(int,input().split())
lis = list(map(int, input().split()))
diff(lis,n)
for i in range(p):
    a,b,c=map(int,input().split())
    d[a-1]+=c
    d[b-1]+=c
print(diff(lis,n))
##报错,

在使用函数返回值的地方并没有使用该返回值,而是再次调用了 diff() 函数。这意味着你没有保存函数调用的结果,而是再次计算了一遍,因此实际上没有使用之前计算的结果。

def diff(a, n):
    d = [0] * n
    d[0] = a[0]
    for i in range(1, n):
        d[i] = a[i] - a[i - 1]
    return d
n, p = map(int, input().split())
lis = list(map(int, input().split()))
# 调用 diff 函数计算差值数组
d = diff(lis, n)
# 进行更新操作
for _ in range(p):
    a, b, c = map(int, input().split())
    d[a - 1] += c
    d[b-1] -= c
# 更新学生的分数
for i in range(n):
    if i == 0:
        lis[i] = d[i]
    else:
        lis[i] = d[i] + lis[i - 1]
# 打印最低分
print(d)
#RE

上面RE,原因要判断过界没有,if b<n: 

def diff(a, n):
    d = [0] * (n+1)
    d[1] = a[1]
    for i in range(2, n):
        d[i] = a[i] - a[i - 1]
    return d

n, p = map(int, input().split())
lis = [0] + list(map(int, input().split()))
# 调用 diff 函数计算差值数组
d = diff(lis, n)
# 进行更新操作
for i in range(p):
    a, b, c = map(int, input().split())
    d[a] += c
    if b+1<n+1:
        d[b+1] -= c
# 更新学生的分数
for i in range(1,n+1):
    if i == 1:
        lis[i] = d[i]
    else:
        lis[i] = d[i] + lis[i - 1]
# 打印最低分
print(min(lis[1:]))

#60
# 定义常量
N = 5 * (10 ** 6) + 10
# 初始化最终答案数组和差分数组
a = [0] * N
b = [0] * N
# 读取输入的学生数和增加分数的次数
n, p = map(int, input().split())

# 读取学生的初始成绩
a[1:n + 1] = map(int, input().split())
# 计算差分数组
for i in range(1, n + 1):
    b[i] = a[i] - a[i - 1]
# 更新差分数组
for _ in range(p):
    x, y, z = map(int, input().split())
    b[x] += z
    if y + 1 < N:  # 防止越界
        b[y + 1] -= z
# 计算最小值
ans = float('inf')  #在Python中,float('inf')
for i in range(1, n + 1):
    b[i] += b[i - 1]
    ans = min(ans, b[i])
# 输出最小值
print(ans)
#80

P3397 地毯

二维前缀和的处理     差分法~超详细(公式+原理+例题)

m, n = map(int, input().split())
lst = [[0] * (m+1) for _ in range(m)]

for _ in range(n):
    x1, y1, x2, y2 = map(int, input().split())
    for i in range(x1-1,x2):
        lst[i][y1-1]+=1
        if y2<m:
            lst[i][y2]-=1

for i in range(m):
    for j in range(m):
        lst[i][j+1]=lst[i][j+1]+lst[i][j]


for i in range(m):
    for j in range(m):
        print(lst[i][j],end=" ")
    print()

P1496 火烧赤壁

# 读取起火的信息条数
n = int(input())

# 初始化结果变量
total_length = 0

# 存储所有起火位置的区间
intervals = []

# 处理每个起火位置的起点和终点,并存储区间信息
for _ in range(n):
    a, b = map(int, input().split())
    intervals.append((a, b))

# 将区间按起点排序
intervals.sort()

# 合并重叠的区间
merged_intervals = [intervals[0]]
for interval in intervals[1:]:
    if interval[0] <= merged_intervals[-1][1]:  # 检查当前区间与上一个合并后的区间是否有重叠
        merged_intervals[-1] = (merged_intervals[-1][0], max(merged_intervals[-1][1], interval[1]))  # 合并区间
    else:
        merged_intervals.append(interval)  # 不重叠,添加新区间

# 计算合并后的区间总长度
for start, end in merged_intervals:
    total_length += end - start

# 输出结果
print(total_length)

P2004 领地选择

N, M, C = map(int, input().split())

# 读取地图上每个地块的价值
map_values = []
for _ in range(N):
    row = list(map(int, input().split()))
    map_values.append(row)

max_total_value = -float('inf')
capital_x = 0
capital_y = 0

# 遍历所有可能的首都位置
for x in range(N - C + 1):
    for y in range(M - C + 1):
        total_value = 0
        # 计算当前首都位置内的地块总价值
        for i in range(x, x + C):
            for j in range(y, y + C):
                total_value += map_values[i][j]
        # 更新最大总价值及对应的首都位置
        if total_value > max_total_value:
            max_total_value = total_value
            capital_x = x + 1  # 转换为1-based索引
            capital_y = y + 1

# 输出结果
print(capital_x, capital_y)

#56,超时

P1904 天际线

。。。持续更新。。。

  • 46
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值