Codeforces 1671-D: Insert a Progression

Codeforces 1671-D: Insert a Progression

题目链接:Codeforces 1671-D: Insert a Progression

题目

题目截图

在这里插入图片描述

样例描述

在这里插入图片描述

题目大意

  给定 x x x 和一个长度为 n n n 的数组 a i a_i ai,将 [ 1 , x ] [1, x] [1,x] 的整数都插入到数组中,可以插入一个数到数组中的任意位置(包括所有数前和所有数后)。设插入数之后的新数组为 a ′ a' a,求 ∑ i = 1 n + x − 1 ∣ a i ′ − a i + 1 ′ ∣ \sum_{i=1}^{n+x-1}|a_{i}' - a_{i+1}'| i=1n+x1aiai+1 的最小值。

题目解析

  很容易发现,若将 z ∈ [ x , y ] z \in [x, y] z[x,y] 插入 x , y x, y x,y 之间,那么得到的差值绝对值和是不变的,即 ∣ x − y ∣ = ∣ x − z ∣ + ∣ z − y ∣ |x-y|=|x-z|+|z-y| xy=xz+zy。这个现象其实还有更进一步的表现,对于数组 a 1 , a 2 , ⋯   , a n a_1,a_2,\cdots,a_n a1,a2,,an,若 a 1 ≤ z ≤ a n a_1 \le z \le a_n a1zan,那么存在 i ∈ ( 1 , n ] i \in (1, n] i(1,n] ,将 z z z 插入到 i − 1 , i i-1,i i1,i 之间,将不会带来额外的差值绝对值和。因为假设我们随机在 ( 1 , n ) , n > 2 (1,n),n>2 (1,n),n>2 之间选择一个位置 j j j,那么 z ∈ [ a 1 , a n ] z \in [a_1,a_n] z[a1,an] 必然在 a 1 , a j a_1,a_j a1,aj a j , a n a_j, a_n aj,an 之间,这样我们可以不断地将整个区间的长度减小,最终只剩下两个数,也就满足了上述理论。
  由于 1 , x 1,x 1,x 都要插入到数组中,因此,这个问题就变成了一个更简单的问题:如何插入 1 , x 1,x 1,x,使得目标最小(因为其它的数都可以对结果不带来任何的增加)。假设 1 1 1 x x x 之前,这样我们其实可以暴力查找 x x x 的位置,并记录在该位置之前带来最小增量的 1 1 1 的位置,并不断比较最小答案,特别地,要考虑 1 , x 1,x 1,x 在同一个间隙及 1 1 1 在整个数组之前, n n n 在整个数组之后的情况。 对于 1 1 1 x x x 之后的情况,我们可以把整个数组反转一下,重复上述过程即可。

Code

#include <bits/stdc++.h>
using namespace std;

#define ins(i,j,x) -abs(a[i]-a[j])+abs(a[i]-x)+abs(x-a[j])

typedef long long LL;
const int maxn = 2e5 + 7;
int a[maxn];

int main() {
    int t, n, x;
    cin >> t;
    while(t--) {
        cin >> n >> x >> a[1];
        LL sum = 0, ans = 0x7fffffffffffffff;
        for(int i=2; i<=n; ++i)
            cin >> a[i], sum += abs(a[i] - a[i-1]);
        for(int _=2; _>0; reverse(a+1, a+n+1), --_) {
            ans = min(ans, sum + x - 1 + abs(a[1] - x));
            int p1=abs(1-a[1]);
            for(int i=2; i<=n; ++i) {
                ans = min(ans, sum - abs(a[i] - a[i-1]) + abs(a[i-1] - 1) + abs(a[i] - x) + x - 1);
                ans = min(ans, sum + p1 + ins(i-1, i, x));
                p1 = min(p1, ins(i-1, i, 1));
            }
            ans = min(ans, sum + p1 + abs(x - a[n]));
        }
        cout << ans << endl;
    }
    return 0;
}```

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值