Santa Claus and Tangerines

时间:2023-03-09 16:01:11
Santa Claus and Tangerines

Santa Claus and Tangerines

题目链接:http://codeforces.com/contest/752/problem/E

二分

显然直接求答案并不是很容易,于是我们将其转化为判定性问题:二分解x,验证是否能分成k个x。

于是要点就在于check函数:

由于奇偶的原因,每个ai分出来的并不是2的幂次(比如当ai=11,x=3时,可以将ai分成3部分5,3,3)。

但是稍作思考,可以发现还是与2的幂次有关:

例如,当ai=6:48,x=3时,

ai part1 part2 num
6 3 3 2
       
10 5 5 2
11 5 6 3
12 6 6 4
       
20 10 10 4
21 10 11 5
22 11 11 6
23 11 12 7
24 12 12 8
       
40 20 20 8
41 20 21 9
42 21 21 10
43 21 22 11
44 22 22 12
45 22 23 13
46 23 23 14
47 23 24 15
48 24 24 16

若ai=44,因为40<=ai<=48,故num=16-(48-ai);

若ai=38,因为24<=ai<40,故num=8.

这种做法的时间复杂度为O(n×lgA×lglgA)

代码如下:

 #include<cstdio>
#include<algorithm>
#define N 1000005
using namespace std;
typedef long long ll;
ll n,k,a[N],p[];
void init(){
p[]=;
for(ll i=;i<;++i)
p[i]=p[i-]<<;
}
bool check(ll x){
if(!x)return ;
ll sum=;
for(ll i=;i<n;++i){
ll t=a[i]/x;
ll up=*upper_bound(p,p+,t);
if(up*x-up/<=a[i])sum+=up-(up*x-a[i]);
else sum+=up/;
}
return sum>=k;
}
int main(void){
scanf("%I64d%I64d",&n,&k);
init();
for(ll i=;i<n;++i)scanf("%I64d",a+i);
ll l=,r=,mid;
while(l+<r){
mid=(r-l)/+l;
if(check(mid))l=mid;
else r=mid-;
}
if(check(r))printf("%I64d\n",r);
else if(check(l))printf("%I64d\n",l);
else printf("-1\n");
}