[題解] CF1392F Omkar and Landslide
阿新 • • 發佈:2020-08-17
結論題。
首先,最後的位置和操作的順序沒有關係,可以按照任意的順序操作。
顯然最後 \(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\) 或不變(高度形如 \(0, 0, 2\) 等)。
有了這個結論,就很容易由 \(\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; }