Nap Sort G
Bessie 正在尝试使用她自己的排序算法对一个整数数组进行排序。她有一堆共 N(1≤N≤2⋅105)个整数a1,a2,…,aN(1≤ai≤1011),她将会按排序顺序将这些数放入一个单独的数组中。她反复查找这堆数中的最小数,将其删除,同时将其添加到数组的末尾。Bessie 在 p 个数的堆中找到最小数需要花费 p 秒。
Farmer John 命令了农场中其他一些奶牛帮助 Bessie 完成任务,她们很懒,然而 Bessie 利用了这一点。她将整数分成两堆:Bessie 堆和助手堆。对于 Bessie 堆中的每个整数,她会正常执行她的算法。对于助手堆中的每个整数,她将其分配给不同的助手奶牛。Farmer John 有一个很大的农场,所以 Bessie 可以找来任意多的助手奶牛。如果助手收到整数 ai,Bessie 会指示该牛小睡 ai 秒,并在她们醒来时立即将该整数添加到数组末尾。如果 Bessie 和一个助手同时向数组添加整数,Bessie 的整数将优先被添加,因为她是领导者。如果多个助手被分配了相同的整数,她们会同时将多个该整数添加到数组中。
请帮助 Bessie 划分她的数,使得最终得到的数组是排序的,并使得排序该数组所需的时间最少。
可以发现无论Bessie手里拿多少个数,都是有解的情况。区别在于假如Bessie拿的很少,她可能很早就放完了,所需时间为a数组的最大值;假如Bessie拿了很多,以至于她能够在最后一个放,那么时间为(p+1)*p/2。
我们去讨论Bessie放最后一个情况:Bessie在第p时间放第一个数,在此之前的所有小于p的数都应该都要被放完;在p+(p-1)的时间放第二个数,在此之前小于2*p-1 的数都应该被放完...... 在(p+1)*p/2的时间放最后一个数,在此之前所有的数都应该被放完。如果我们发现在Bessie放完数之后还有数没放,那么这个p就不属于我们讨论的[Bessie放最后一个]的情况。
同时我们发现Bessie可以拿的数具有单调性质,所以我们可以二分去查找Bessie可以拿的数。
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int a[N], b[N], f[N];
int n, m, c;
bool check(int x) {
int tim = 0 ;
for(int i=1; i<=n; i++) {
if(x==0)return false;
if(a[i]>=tim+x) {
tim += x;
x--;
}
}
return true;
}
void solve() {
cin>>n;
for(int i=1; i<=n; i++)cin>>a[i];
sort(a+1,a+1+n);
int ans = a[n];
int l =1 ,r = sqrt(a[n]);
while(l<=r) {
int mid = (l+r)/2ll;
if(check(mid)) {
r = mid -1;
} else l=mid+1;
}
if(check(l)) {
ans= min(ans,l*(l+1)/2ll);
} else if(check(r))ans = min(ans,r*(r+1)/2ll);
cout<<ans<<'\n';
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T = 1;
cin >> T;
while (T--)solve();
return 0;
}