题目解法
倒过来考虑题目中的过程,即从全零数组开始,进行题目中操作的拟操作。
则应当每次找到数组中最低的为
0
0
0 的位置
i
i
i ,令
a
i
=
i
,
a
j
=
a
j
−
1
(
j
≤
i
−
1
)
a_i=i,a_j=a_j-1\;(j\leq i-1)
ai=i,aj=aj−1(j≤i−1) 。
给定操作次数
X
X
X ,考虑如何高效地还原出
X
X
X 次操作后的数组。
我们称一次操作
a
i
=
i
,
a
j
=
a
j
−
1
(
j
≤
i
−
1
)
a_i=i,a_j=a_j-1\;(j\leq i-1)
ai=i,aj=aj−1(j≤i−1) 为操作
i
i
i 。
则第
1
,
3
,
5
,
…
1,3,5,\dots
1,3,5,… 次操作应当为操作
1
1
1 ;
删除所有操作
1
1
1 后,第
1
,
4
,
7
,
…
1,4,7,\dots
1,4,7,… 次操作应当为操作
2
2
2 ;
删除所有操作
1
,
2
1,2
1,2 后,则第
1
,
5
,
9
,
…
1,5,9,\dots
1,5,9,… 次操作应当为操作
3
3
3 ……
因此,我们可以求出
X
X
X 次操作后,序列的长度
N
N
N 。
由于序列的长度并不确定,我们可以通过上述过程二分求出序列的长度。
不难发现,序列的长度
N
=
O
(
K
)
N=O(\sqrt{K})
N=O(K) ,在
K
≤
1
0
12
K\leq 10^{12}
K≤1012 时,
N
≤
2
×
1
0
6
N\leq 2\times 10^6
N≤2×106 。
事实上, 一篇论文 指出,
N
→
+
∞
N\rightarrow+\infty
N→+∞ 时,有
N
2
N
+
K
→
π
\frac{N^2}{N+K}\rightarrow\pi
N+KN2→π ,可以对
N
N
N 进行一个较为精确的估计。
时间复杂度 O ( K L o g K ) O(\sqrt{K}LogK) O(KLogK) 。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e6 + 5;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
ll k, ans[MAXN];
int check(int mid) {
int ans = 0; ll tmp = k + mid;
while (tmp != 0) {
ans++;
ll mns = tmp / (ans + 1) + (tmp % (ans + 1) != 0);
tmp -= mns;
}
return ans;
}
int main() {
int n, last; read(k);
if (k <= 1e11) {
int l = 1, r = 2e6;
while (true) {
int mid = (l + r) / 2;
int tmp = check(mid);
if (tmp == mid) {
l = r = mid;
break;
}
if (tmp > mid) l = mid + 1;
else r = mid - 1;
} n = l;
} else {
n = check(2e6), last = 2e6;
while (n != last) {
last = n;
n = check(n);
}
}
ll tmp = k + n;
printf("%d\n", n);
for (int i = 1; i <= n; i++) {
ll mns = tmp / (i + 1) + (tmp % (i + 1) != 0);
ans[1] -= mns, ans[i] += mns;
ans[i] += mns * i, ans[i + 1] -= mns * i;
tmp -= mns;
}
for (int i = 1; i <= n; i++) {
ans[i] += ans[i - 1];
printf("%lld ", ans[i]);
}
printf("\n");
return 0;
}