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|
∣a1−b1∣+∣a2−b2∣+⋅⋅⋅+∣an−bn∣最小。
输入格式:
第一行为数字
n
(
1
≤
n
≤
1
0
6
)
n(1≤n≤10^6)
n(1≤n≤106),接下来一行共有
n
n
n个数字,表示序列
a
i
(
0
≤
a
i
≤
2
×
1
0
9
)
a_i (0≤a_i≤2×10^9)
ai(0≤ai≤2×109)。
输出格式:
第一行输出最小的绝对值之和。
第二行输出序列
b
i
b_i
bi,若有多种方案,只需输出其中一种。
数据范围:
40
%
40\%
40%的数据
n
≤
5000
n≤5000
n≤5000;
60
%
60\%
60%的数据
n
≤
300000
n≤300000
n≤300000;
100
%
100\%
100%的数据
n
≤
1000000
,
0
≤
a
i
≤
2
×
1
0
9
n≤1000000, 0≤a_i≤2×10^9
n≤1000000,0≤ai≤2×109;
参考https://blog.csdn.net/qq_46105170/article/details/126434875
。代码如下:
#include
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)。