同我在洛谷的博客
首先,我们从枚举入手。
枚举 s s s 从 1 1 1 到 a [ n ] a[n] a[n] (数组最大值)。
再用贪心法求所需盒子的数量。
(贪心的解法待会儿再讲)
但我们发现:会超时.
枚举 O ( max ( s [ i ] ) ) O(\max(s[i])) O(max(s[i])) ,验证 O ( n ) O(n) O(n)
不超时才怪
我们又发现:这符合二分答案的性质(线性)
所以,就想到了二分。
二分,我们得先确定左指针和右指针的初始值。
(答案的区间)
答案一定会在 a[n]
(最大的必须得装)和 a[n]+a[n-1]
(不会又比它们更大的物品和)中。
所以,二分的主体就出来了。
long long l=a[n],r=a[n]+a[n-1];
while(l<=r){
long long mid=(l+r)/2;
if(find(mid)){
l=mid+1;
}
else{
r=mid-1;
}
}
cout<<l;
接下来,我们看 c h e c k check check 函数。
贪心法:双指针。
双指针,就是 l l l 和 r r r 两个下标。
先测试当前 a [ l ] + a [ r ] a[l]+a[r] a[l]+a[r] 是否小于等于 m i d mid mid 。
若小于等于,则这两个物品放在一个盒子里;
否则,移动右指针,将右指针放一个盒子。
最后,返回 a n s > k ans>k ans>k (当前尺寸是否合法)。
检验函数:
bool find(long long mid){
int ans=0;
int l=1,r=n;
while(l<=r){
if(a[l]+a[r]<=mid){
l++;
r--;
ans++;
}
else{
r--;
ans++;
}
}
return ans>k;
}
最后的最后,放一下完整的 A C AC AC 代码。
C o d e Code Code:
#include<iostream>
using namespace std;
int a[100005];
int n;
int k;
bool find(long long mid){
int ans=0;
int l=1,r=n;
while(l<=r){
if(a[l]+a[r]<=mid){
l++;
r--;
ans++;
}
else{
r--;
ans++;
}
}
return ans>k;
}
int main(){
cin>>n;
cin>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
}
long long l=a[n],r=a[n]+a[n-1];
while(l<=r){
long long mid=(l+r)/2;
if(find(mid)){
l=mid+1;
}
else{
r=mid-1;
}
}
cout<<l;
return 0;
}