这题是训练时队友写的 自己就没想到...
感觉二分很神奇 可以把很多复杂的问题简化成一个判定性的问题 在简化问题之后很多原本不可知的东西就变成已知量 从而可以找到更简单的方法来解决简化的问题 然后由这个问题的执行结果决定下一步该怎么做
上面是去年说的废话
二分一个时间 把所有建筑任务都堆到最后放 比如当前二分的时间是lim 任务执行时间是t[i] 则最晚开始时间为lim-t[i] 然后跟着时间走 每碰到一个任务起始时间就从蛋里拿只蚂蚁干活 剩下的继续孵化 即每过k时间就将剩下的蚂蚁数量翻倍
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll N=0x3f3f3f3f3f3f3f3f;
const int maxn=1e5+10;
struct node
{
ll cnt,val;
};
node ary[maxn];
ll pre[100];
ll m,k,tot;
int n;
void init()
{
int i;
pre[0]=1;
for(i=1;i<=60;i++){
pre[i]=2*pre[i-1];
}
}
bool cmp(node n1,node n2)
{
return n1.val>n2.val;
}
bool judge(ll lim)
{
ll cnt,cur;
int i;
cnt=m,cur=0;
for(i=1;i<=n;i++){
if(cur/k<(lim-ary[i].val)/k){
if((lim-ary[i].val)/k-cur/k>=20) return 1;
cnt*=pre[(lim-ary[i].val)/k-cur/k];
if(cnt>=tot) return 1;
cur+=k*((lim-ary[i].val)/k-cur/k);
}
cnt-=ary[i].cnt;
if(cnt<0) return 0;
}
return 1;
}
int main()
{
ll l,r,mid,ans;
int t,i,j;
init();
scanf("%d",&t);
while(t--){
scanf("%d%I64d%I64d",&n,&m,&k);
tot=n;
for(i=1;i<=n;i++){
scanf("%I64d",&ary[i].val);
}
sort(ary+1,ary+n+1,cmp);
for(i=1,j=0;i<=n;i++){
if(j==0||ary[j].val!=ary[i].val){
ary[++j].val=ary[i].val;
ary[j].cnt=1;
}
else ary[j].cnt++;
}
n=j;
/*
for(i=1;i<=n;i++){
printf("%lld %lld\n",ary[i].val,ary[i].cnt);
}
*/
l=ary[1].val,r=1e12;
while(l<=r){
mid=(l+r)/2;
if(judge(mid)){
r=mid-1,ans=mid;
}
else{
l=mid+1;
}
}
printf("%I64d\n",ans);
}
return 0;
}
/*
1
3 1 1
1 3 5
*/