AcWing 3993. 取石子
取石子
题意
有 \(n\) 堆石子,每堆有 \(a_1, a_2, a_3...a_n\) 个石子,进行若干轮,使得每堆石子的数量相同。
每一轮:选择一个限定值 \(h\) ,将所有石子数量大于 \(h\) 的堆去除直到剩下 \(h\) 个石子。注意每一轮去除的石子数量不能超过 \(k\) 。
给定 \(n、k\) 与每堆石子的数量,求最少进行几轮可以达成目标。
\(1 \le n \le 2 \times 10^5, n \le k \le 10^9, 1 \le a_i \le 2 \times 10^5\) 。
分析
从高度最大的石子堆开始取,如果能取的数量不超过 \(k\) ,那么累加到下一次,否则轮数加一。
Code
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 200010;
int n, k;
int cnt[N];
int main ()
{
cin >> n >> k;
int v = 2e6, m = 0;
for (int i = 1, x; i <= n; i ++ ) cin >> x, cnt[x] ++ , v = min(v, x), m = max(m, x);
// 如果初始相同高度,那么不需要轮次
if (v == m) { puts("0"); return 0; }
long long cnts = 0;
int ans = 0;
// 从最大堆开始,直到最小堆,因为最后的状态一定使全v
for (int i = m; i > v; i -- )
{
// 贪心:当石子个数累计超过 k 时才进行一轮操作,取出高度大于 i 的剩余石子
if (cnts + cnt[i] > k)
{
cnts = cnt[i];
ans ++ ;
}
else cnts += cnt[i];
// 当前的剩余石子累加到下一层
cnt[i-1] += cnt[i];
}
// 最后剩余的cnts再每个取一个,进行一次操作
cout << ans + 1 << endl;
return 0;
}