P10139 [USACO24JAN] Nap Sort G 题解
G组练习总结#13
场切题!USACO 真的很喜欢放二分题目(笑)。
题目大意
Bessie 又在制造麻烦事!
她现在有一个长度为
具体来说,她的排序方法是:
首先,她会新建一个数组
然后 Bessie 会自己选取一些数自己处理,假设她目前手上有
简单来说,设一开始的集合大小是
但她还有另一种选择,她可以把数交给朋友们来操作,朋友们很懒,假设他们拿到的数是
加入的时候,如果 Bessie 和朋友同时加数,Bessie 优先级更高。
现在 Bessie 也想去睡觉啦(不是),她想知道最短的加入所有数的时间。
数据有
解题思路(暴力)
处理肯定按照顺序,所以我们可以直接将
我们考虑最后一个数
因此,我们考虑枚举集合大小
至于向集合内加数需要满足,比如,加第一个时,我们要把
为什么要这样?因为 Bessie 加入的第一个数肯定在
而且注意,因为 Bessie 的优先级大于朋友们,所以如果她们同时在
对于其他的情况,也都是这样处理,依次处理完所有
时间复杂度
参考代码(暴力)
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=2e5+5;
typedef long long ll;
int t,n,c;
ll a[N],m,p;
int main() {
int i,j;
scanf("%d",&t);
while(t) {
--t;
scanf("%d",&n);
for(i=1; i<=n; ++i)
scanf("%lld",a+i);
sort(a+1,a+n+1);
m=a[n];
for(j=1; 1ll*(j+1)*j/2<=a[n]; ++j) {//枚举集合大小p
c=j;
p=0;
for(i=1; i<=n; ++i) {
if(!c)
break;
if(a[i]>=p+c) {//依次往集合里面塞数
p=p+c;//记录当前Bessie加数的时间
--c;
}
if(i==n)
m=min(m,1ll*j*(j+1)/2);//找答案
}
if(m<a[n])
break;
}
printf("%lld\n",m);
}
return 0;
}
解题思路(正解)
突然发现几乎没有什么好说的啊……
这个题目的答案具有单调性啊,集合大小的可行性是有单调性的?
没错,这个也挺好想的,越大的集合我们就可以处理更多数!
这么好的代码(不是),一改就可以适应一个二分对吧!
新的时间复杂度
参考代码(正解)
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=2e5+5;
typedef long long ll;
int t,n,l,r,d;
ll a[N],m,p;
int check(int c) {
int i;
p=0;
for(i=1; i<=n; ++i) {
if(!c)
return 0;
if(a[i]>=p+c) {
p=p+c;
--c;
}
}
return 1;
}
int main() {
int i,j;
scanf("%d",&t);
while(t) {
--t;
scanf("%d",&n);
for(i=1; i<=n; ++i)
scanf("%lld",a+i);
sort(a+1,a+n+1);
m=a[n];
l=1,r=sqrt(a[n]);
while(l<=r) {//只不过改了,枚举变成二分就好啦~
d=l+r>>1;
if(check(d)) {
r=d-1;
m=1ll*d*(d+1)/2;
} else
l=d+1;
}
printf("%lld\n",m);
}
return 0;
}