3995 最小的和(多路归并)

本文介绍了一种解决给定整数序列a和b的优化问题,通过分析得知对操作次数的充分利用可以使得(a-b)^2和达到最小。关键策略在于利用多路归并思想,计算并优先处理绝对值最大的差值。代码实现展示了如何通过d数组管理和操作次数判断来求得最优解。
摘要由CSDN通过智能技术生成

1. 问题描述:

给定两个长度为 n 的整数序列 a1,a2,…,an 和 b1,b2,…,bn。现在要对序列 a 进行恰好 k1 次操作,对序列 b 进行恰好 k2 次操作。每次操作具体流程为选取序列中的一个元素,并将其加 1 或减 1。要求所有操作进行完毕以后,∑i=1n(ai−bi) ^ 2 尽可能小。

输入格式

第一行包含三个整数 n,k1,k2。第二行包含 n 个整数 a1,a2,…,an。第三行包含 n 个整数 b1,b2,…,bn。

输出格式

一个整数,表示所有操作进行完毕以后,∑i=1n(ai−bi) ^ 2 的最小可能值。

数据范围

前六个测试点满足,1 ≤ n ≤ 5。
所有测试点满足,1 ≤ n ≤ 10 ^ 3,0 ≤ k1 + k2 ≤ 10 ^ 3,k1 和 k2 都是非负整数,−10 ^ 6 ≤ ai,bi ≤ 10 ^ 6。

输入样例1:

2 0 0
1 2
2 3

输出样例1:

2

输入样例2:

2 1 0
1 2
2 2

输出样例2:

0

输入样例3:

2 5 7
3 4
14 4

输出样例3:

1
来源:https://www.acwing.com/problem/content/description/3998/

2. 思路分析:

对于这种题目需要一步一步进行分析,因为最终需要使得(ai - bi) ^ 2的和最小,而每一次操作只是对ai - bi的绝对值产生影响,所以对于当前的第i个位置不管是对ai还是对bi操作都是绝对值减1,所以对a操作和对b操作是完全等价的,所以不需要分对谁操作,所以总的操作次数为m = k1 + k2即可,我们可以先求解一下每一个ai与bi差的绝对值,令ai与bi差的绝对值为x0,x1,x2,....xn-1,我们可以计算出每一次xi减1之后能够减少的差值是多少:

因为需要使得最终的总和最小所以使应该要令每一次操作之后减去的值最大,所以相当于是在总共有n个有序序列,这些序列中选择前m个最大值,可以发现这是一个经典的模型---多路归并,一般这种模型考察的都会比较隐晦,需要一步步分析才可以得到最终的模型。我们可以使用d数组来记录每一个ai与bi差的绝对值,每一次找到绝对值最大的位置,如果当前的di大于0那么令其减1,如果最大值已经变为0了那么考虑剩余的操作次数,如果剩余的操作次数为偶数那么我们可以通过对其中某个位置进行加1和减1的操作最终结果为0,如果为奇数那么一定要选择一个位置对其操作,所以最终的结果为1,最终我们还需要将剩余的d[i]的平方累计到答案中(因为数据规模不是特别大所以可以直接枚举计算出所有d[i]的最大值,如果数据规模比较大多路归并一般使用堆来维护)。

3. 代码如下:

class Solution:
    # 多路归并
    def process(self):
        n, k1, k2 = map(int, input().split())
        m = k1 + k2
        a = list(map(int, input().split()))
        b = list(map(int, input().split()))
        # d记录a与b差值的绝对值
        d = list()
        for i in range(n):
            d.append(abs(a[i] - b[i]))
        res = 0
        for i in range(m):
            t = 0
            # 求解当前绝对值最大的位置t
            for j in range(n):
                if d[j] > d[t]:
                    t = j
            if d[t] == 0:
                # 最大值已经变为0了所以记录对应的答案, 如果为奇数那么答案为1为偶数则答案为0
                res = (m - i) % 2
                break
            # 当前最大值的位置减去1
            d[t] -= 1
        for i in range(n):
            # 计算剩余的结果
            res += d[i] * d[i]
        return res


if __name__ == '__main__':
    print(Solution().process())
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值