CF ECR 126 C. Water the Trees(二分答案)
传送门
自己想了一个结论,结果假了
求极值,而且答案有单调性,复杂度允许,应该想到要二分答案的。
答案只可能是树的最大高度\(Max \_ H\)或者\(Max \_ H+1\)
因为使所有树高度相同为\(H\)的最优操作最多空出来\(n-1\)天\(([1,1,1,1,2])\),但是使所有树高度相同为\(H+2\)不能在树的高度全是\(H\)的情况下只用\(n-1\)次操作实现.
二分答案的判断时考虑有x次机会使数的高度加2,有y次机会加1,使用能用+2就用+2的思路判断。
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define int long long
const int N=301000;
int w[N],a[N],n;
int read(){
int sum=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
sum=sum*10+ch-'0';
ch=getchar();
}
return sum*f;
}
bool judge(int x){
int num_2=x/2;
int num_1=x-num_2;
for(int i=1;i<=n;i++){
int num=min(num_2,a[i]/2);
num_2-=num;
num_1-=a[i]-num*2;
if(num_1<0||num_2<0)return false;
}
return true;
}
signed main(){
int T=read();
while(T--){
n=read();
int Ans=1e18;
int Mx=0;
for(int i=1;i<=n;i++)w[i]=read(),Mx=max(Mx,w[i]);
for(int j=0;j<=1;j++){
int mx=j+Mx;
for(int i=1;i<=n;i++)a[i]=mx-w[i];
int L=0,R=1e18;
int ans=R;
while(L<=R){
int mid=(L+R>>1);
if(judge(mid)){
ans=mid;
R=mid-1;
}
else L=mid+1;
}
Ans=min(Ans,ans);
}
cout<<Ans<<endl;
}
return 0;
}