T5_Santa Claus and Tangerines (二分 & 递推)
——题意——
有n个橘子和k个小朋友,要求每个小朋友都分到橘子,满足的所有方案中,分得橘子最小的小朋友,拿到的橘子最大为多少?
分橘子规则有两条:
①橘子只能对半分,假设第
i
i
i橘子大小为
a
i
ai
ai,若
a
i
ai
ai为偶数,则分成两份的
a
i
/
2
ai/2
ai/2;若为奇数,分成两份一个比另一个大
1
1
1。大小只有
1
1
1的橘子不能分。
②每个小朋友只能拿一整个橘子或一个橘子的某一部分,即不能拼凑。
——题解——
很容易想到这是个二分,粗略估算一下
n
l
o
g
n
nlogn
nlogn的复杂度足以应付这个数据量。
问题是如何制作check函数,此处我用了递推的方式。设尝试的值为
b
a
s
e
base
base,当橘子大小为
b
a
s
e
base
base时,理所当然只能分给一个小朋友。当橘子大小为
i
i
i时,它可以由
i
/
2
i/2
i/2和
(
i
+
1
)
/
2
(i+1)/2
(i+1)/2两部分组成,所以能分的数量也即这两种情况之和。从
b
a
s
e
base
base到
m
a
x
(
a
i
)
max(ai)
max(ai),把这些橘子大小可以分成的人数依次递推出。然后对
a
[
i
]
a[i]
a[i]进行枚举累加。
建议用快速读入。
——Code——
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
int n,k;
long long len;
long long f[10000007];
long long a[1000006];
bool check(int base)
{
long long cnt=0;
for(int i=0;i<=len;++i)
f[i]=0;
for(int i=base;i<=len;++i)
f[i]=max(f[i/2]+f[(i+1)/2],(long long)1);
for(int i=1;i<=n;++i)
{
cnt+=f[a[i]];
if(cnt>=k)
return true;
}
return false;
}
bool cmp(long long p1,long long p2)
{
return p1>p2;
}
int main()
{
cin>>n>>k;
long long left=1,right=-1;
for(int i=1;i<=n;++i)
{
scanf("%I64d",&a[i]);
right=max(right,a[i]);
}
len=right;
// sort(a+1,a+n+1,cmp);
long long ans=0;
while(left<=right)
{
long long mid=(left+right)/2;
if(check(mid))
{
left=mid+1;
ans=mid;
}
else right=mid-1;
}
if(ans==0) printf("-1\n");
else printf("%I64d\n",ans);
return 0;
}