CF1661C Water the Trees
题意
有一个 个数的整数序列 ,你可以花总共 天时间,在第 天进行如下操作之一:
- 若 为奇数,将任意一个 增加 。
- 若 为偶数,将任意一个 增加 。
- 啥也不干。
求 最小为多少时存在一种操作方法可以使所有 相等。
分析
设 ,那么答案的方案中所有 最后都会变成 或 之一,显然更大的 都不如这两个优。
设最后所有的 都变成了 ,那么问题就转化为了求最小的 ,每天按照规则将 减少使得最后所有的 都等于 。
显然 满足单调性,即 小于答案时无法使所有 ,大于等于时则可以,因此我们可以二分答案转求解为判定,而判定相当容易,设二分到 ,那么我们就有 个 和 个 进行操作,根据贪心的想法,能用 就用 ,实在不行再用 ,如果走投无路了则说明无法满足要求。
值得注意的是,二分的 不要开太小,至少要到 ,不然会 WA;而且每次二分时要重置 数组。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
long long read(){
long long x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
void write(long long x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int N=3e5+10;
int t,n;
ll h[N],d[N],ans,mx,l,r;
ll od,ed;//奇偶
bool check(ll x){
od=(x+1)>>1;
ed=x>>1;
for(int i=1;i<=n;i++){
d[i]=mx-h[i];
if(ed*2>=d[i]){
ed-=d[i]/2;
d[i]=d[i]%2;
}
else{
d[i]-=ed*2;
ed=0;
}
if(d[i]>od)
return 0;
od-=d[i];
}
return 1;
}
int main(){
t=read();
while(t--){
n=read();
mx=0;
for(int i=1;i<=n;i++){
h[i]=read();
mx=max(mx,h[i]);
}
//第一次二分 m=mx
l=0;r=0;
for(int i=1;i<=n;i++)
r+=mx-h[i];
r*=2;r++;
while(l<r){
ll mid=(l+r)>>1;
if(check(mid))
r=mid;
else
l=mid+1;
}
ans=l;
//第二次二分 m=mx+1
mx++;
l=0;r=0;
for(int i=1;i<=n;i++)
r+=mx-h[i];
r*=2;r++;
while(l<r){
ll mid=(l+r)>>1;
if(check(mid))
r=mid;
else
l=mid+1;
}
printf("%lld\n",min(ans,l));
}
return 0;
}

浙公网安备 33010602011771号