【洛谷】P4331 数字序列

题目地址:

https://www.luogu.com.cn/problem/P4331

题目描述:
给定一个整数序列 a 1 , a 2 , ⋅ ⋅ ⋅ , a n a_1, a_2, ··· , a_n a1,a2,⋅⋅⋅,an,求出一个递增序列 b 1 < b 2 < ⋅ ⋅ ⋅ < b n b_1 < b_2 < ··· < b_n b1<b2<⋅⋅⋅<bn,使得序列 a i a_i ai b i b_i bi的各项之差的绝对值之和 ∣ a 1 − b 1 ∣ + ∣ a 2 − b 2 ∣ + ⋅ ⋅ ⋅ + ∣ a n − b n ∣ |a_1 - b_1| + |a_2 - b_2| + ··· + |a_n - b_n| a1b1+a2b2+⋅⋅⋅+anbn最小。

输入格式:
第一行为数字 n ( 1 ≤ n ≤ 1 0 6 ) n(1≤n≤10^6) n(1n106),接下来一行共有 n n n个数字,表示序列 a i ( 0 ≤ a i ≤ 2 × 1 0 9 ) a_i (0≤a_i≤2×10^9) ai(0ai2×109)

输出格式:
第一行输出最小的绝对值之和。
第二行输出序列 b i b_i bi,若有多种方案,只需输出其中一种。

数据范围:
40 % 40\% 40%的数据 n ≤ 5000 n≤5000 n5000
60 % 60\% 60%的数据 n ≤ 300000 n≤300000 n300000
100 % 100\% 100%的数据 n ≤ 1000000 , 0 ≤ a i ≤ 2 × 1 0 9 n≤1000000, 0≤a_i≤2×10^9 n1000000,0ai2×109

参考https://blog.csdn.net/qq_46105170/article/details/126434875
。代码如下:

#include <iostream>
using namespace std;

const int N = 1e6 + 10;
int n;
long a[N];
long h[N];
int sz;

void sift_up(int k) {
  while (k > 1 && h[k] > h[k >> 1]) {
    swap(h[k], h[k >> 1]);
    k >>= 1;
  }
}

void sift_down(int k) {
  while (k * 2 <= sz) {
    int t = k;
    if (h[k * 2] > h[t]) t = k * 2;
    if (k * 2 + 1 <= sz && h[k * 2 + 1] > h[t]) t = k * 2 + 1;
    if (t == k) return;
    swap(h[k], h[t]);
    k = t;
  }
}

void push(long x) {
  h[++sz] = x;
  sift_up(sz);
}

void pop() {
  h[1] = h[sz--];
  sift_down(1);
}

#define top() h[1]

int main() {
  scanf("%d", &n);
  long res = 0;
  for (int i = 1; i <= n; i++) {
    long x;
    scanf("%ld", &x);
    x -= i;
    push(x);
    if (top() > x) {
      res += top() - x;
      pop();
      push(x);
    }
    a[i] = top();
  }

  printf("%ld\n", res);
  for (int i = n - 1; i; i--) a[i] = min(a[i], a[i + 1]);
  for (int i = 1; i <= n; i++) printf("%ld ", a[i] + i);
  return 0;
}

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn),空间 O ( n ) O(n) O(n)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值