题解系列014 | 洛谷题解 CF1060D 【Social Circles】

原题传送门:Cutting Carrot

题目分析

这题的关键在于不要纠结于局部,而是注重整体。这也是许多看似复杂困难的问题的解法。我们通过追问的方式给出我的思考过程。

  • Q1:座位的排布是否有某种规律?
  • A1:可以分成一段段,段与段之间由客人隔开。
  • Q2:既然要求最小值,那段数能否先把它搞到最小?
  • A2:很遗憾不行。但幸运的是,段数是一个定值。具体而言,每一个圆桌上如果有 m ∈ [ 1 , N ] m\in[1,N] m[1,N] 个人,那么也将有 m m m 个段(圆排列的性质),因此总段数 = N =N =N
  • Q3:那是否有哪些段“阻碍”了最小化?
  • A3:如果某个乘客的舒适空间特别大,那么这一段的最小长度就要大于等于它的舒适空间(非严格表述)。
  • Q4:那么怎么省空间呢?
  • A4:只能左右把空位“抵消”掉,从而分担掉一点舒适空间。

至此,我们已经可以给出一个数学化的表述:假设一个人的左舒适空间 l i , 1 ≤ i ≤ N l_i, 1\leq i\leq N li,1iN, 右舒适空间 r i , 1 ≤ i ≤ N r_i, 1\leq i\leq N ri,1iN, σ \sigma σ { 1 , 2 , ⋯   , N } \{1, 2, \cdots, N\} {1,2,,N} 上的任一置换, 则问题的一种局部解 ∑ i = 1 n max ⁡ { l i , r σ ( i ) } + N 加上一开始的 N 个人 ⏟ \sum\limits_{i=1}^{n}\max\{l_i, r_{\sigma(i)}\}+\underset{\underbrace{\text{加上一开始的 N 个人}}}{N} i=1nmax{li,rσ(i)}+ 加上一开始的 N 个人N。这里若 σ g ( i ) = i \sigma^{g}(i)=i σg(i)=i, 那么就成了一个圈( 1 ≤ g ≤ N 1\leq g\leq N 1gN),简单来说,这种状态一定能构造出来。

容易看出,为了使上式达到最小值,应该让大的和大的配,小的和小的配(直观上也很显然,严格的数学证明只要写一个 2 × N 2\times N 2×N 阵列去分析就行)。于是如果将 { l i } , { r i } \left\{ l_i \right\} ,\left\{ r_i \right\} {li},{ri} 排序为 r 1 ≥ r 2 ≥ ⋯ ≥ r N , l 1 ≥ l 2 ≥ ⋯ ≥ l N r_1\geq r_2\geq \cdots \geq r_N, l_1\geq l_2\geq \cdots \geq l_N r1r2rN,l1l2lN, 则所求的 N + min ⁡ { ∑ i = 1 n max ⁡ { l i , r σ ( i ) } } = N + ∑ i = 1 n max ⁡ { l i , r i } N+\min\{\sum\limits_{i=1}^{n}\max\{l_i, r_{\sigma(i)}\}\} = N+\sum\limits_{i=1}^{n}\max\{l_i, r_i\} N+min{i=1nmax{li,rσ(i)}}=N+i=1nmax{li,ri}。剩下的代码是容易的。

代码(python 3)
class Solution:
    def __init__(self) -> None:
        pass
    
    def solution(self, n, vector):
        left = [vector[i][0] for i in range(n)]
        right = [vector[i][1] for i in range(n)]
        
        left.sort()
        right.sort()
        
        result = n
        for i in range(n):
            result = result + max(left[i], right[i])
        
        return result

if __name__ == "__main__":


    n = int(input().strip())
    
    
    vector = []
    for i in range(n):
        vector.append([int(item) for item in input().strip().split()])
    
    
    sol = Solution()
    result = sol.solution(n, vector)

    print(result)

欢迎关注我的博客!
我的 GitHub 账号: 欢迎 Fork + PR!
我的洛谷账号:这是我
我的洛谷团队:这是我的团队
欢迎大家关注我,在项目上与我协作哦!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值