USACO 24 JAN 补题

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值