n (≤ 200,000) 人排隊買冰淇淋,第 i 人(從隊尾數起)有 aᵢ 元。任意相鄰兩人 a(後)與 b(前),a 可付 1 元給 b 交換位置(a 錢-1,b 錢+1)。目標:調整順序使隊列非嚴格遞增(即前面的人錢數 ≥ 後面的人),輸出最終每人錢數;不可能則輸出 :(。
將每人看作一座塔,高度為其錢數;隊列位置看作樓梯,第 i 階高度為 i(從隊尾 0 開始)。人站在樓梯上時,其「實際高度」= 塔高 + 樓梯高 = aᵢ + i。
交換操作:後人塔移到前一階,前人塔移到後一階。塔高不變,樓梯高互換。因此「實際高度」aᵢ + i 不變!
:(。輸入: 3 / 12 3 3
b = [12+0, 3+1, 3+2] = [12, 4, 5]
排序後 b = [4, 5, 12]
最終錢數 = [4-0, 5-1, 12-2] = [4, 4, 10] ✓
不變量:每人 aᵢ + i 恆定。最終隊列非嚴格遞增 ⇔ 最終 aᵢ 非嚴格遞增 ⇔ bᵢ - i 非嚴格遞增 ⇔ bᵢ 非嚴格遞增(因 i 嚴格遞增)。故只需將 b 排序。若排序後 bᵢ - i 仍非遞增,說明無法滿足條件。
#include
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
if(!(cin >> n)) return 0;
vector b(n);
for (int i = 0; i < n; i++) {
long long a; cin >> a;
b[i] = a + i;
}
sort(b.begin(), b.end());
for (int i = 1; i < n; i++) {
if (b[i] - i < b[i-1] - (i-1)) {
cout << ":(\n";
return 0;
}
}
for (int i = 0; i < n; i++) {
cout << b[i] - i << (i+1==n?'\n':' ');
}
return 0;
}
本題通過「塔+樓梯」模型將交換操作轉化為不變量 aᵢ + i,巧妙避開了複雜的模擬,化歸為簡單的排序問題。體現了競賽編程中「尋找不變量、轉換視角」的核心思想。