[题解] CF1392F Omkar and Landslide
结论题。
首先,最后的位置和操作的顺序没有关系。
显然最后 \(h_{i+1}-h_i \in \{0, 1\}\)。暴力算一些答案,可以发现最后的差分序列中最多有 \(1\) 个 \(0\)。
结论:最后的序列中满足 \(h_i = h_{i+1}\) 的 \(i\) 数量不超过 \(1\)。
证明:
考虑从点 \(i\) 开始向左依次推进的算法:
- 如果 \(i = 1\) 或 \(h_i - h_{i - 1} < 2\),结束;
- 否则 \(h_i \leftarrow h_i - 1, \;h_{i-1} \leftarrow h_{i-1}+1, \;i \leftarrow i-1\),回到第一步递归执行。
执行一次推进后,如果 \(i\) 左边的数互不相等,那么会一直推进到 \(1\),这可能使相等对数增加 \(1\),否则,若 \(h_i = h_{i + 1}\),那么推进操作会在 \(i+1\) 处结束,使相等对数减少 \(1\) 或不变(高度形如 \(x, x, x+2\) 等时个数不变)。
那么依次对 \(2, 3, \dots, n\) 执行推进,就容易发现相等对始终不会超过 \(1\) 对。
有了这个结论,可以发现 \(S = \sum h_i\) 唯一确定了一个最终的高度序列。先假设没有相等对,那么 \(\displaystyle \sum h_i = S = \frac{n(2h_1 + n - 1)}{2}\),解出 \(h_1\)(上取整),再调整其中一个不会增加的位置即可。
参考实现:
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
#define File(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
typedef long long ll;
namespace io {
const int SIZE = (1 << 21) + 1;
char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
char getc () {return gc();}
inline void flush () {fwrite (obuf, 1, oS - obuf, stdout); oS = obuf;}
inline void putc (char x) {*oS ++ = x; if (oS == oT) flush ();}
template <class I> inline void gi (I &x) {for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;}
template <class I> inline void print (I x) {if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;while (x) qu[++ qr] = x % 10 + '0', x /= 10;while (qr) putc (qu[qr --]);}
struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io :: gi; using io :: putc; using io :: print; using io :: getc;
template<class T> void upmax(T &x, T y){x = x>y ? x : y;}
template<class T> void upmin(T &x, T y){x = x<y ? x : y;}
const int N = 1000005;
int main(){
// File("f");
ll s = 0, n = 0;
gi(n);
for(int i=1; i<=n; i++){
ll x;
gi(x);
s += x;
}
ll p = (2 * s - n * (n - 1) - 1) / (n * 2) + 1;
ll ns = (2 * p + n - 1) * n / 2;
ll pos = n - (ns - s);
for(int i=1; i<=pos; i++) print(p + i - 1), putc(' ');
for(int i=pos+1; i<=n; i++) print(p + i - 2), putc(' ');
putc('\n');
return 0;
}