[cf] 1622C - Set or Decrease 二分

前言

传送门 :

题意 :

给你一个 n n n k k k,以及一个长度为 n n n a [ ] a[] a[]

两种操作 :

  • 选择一个下标使得 a [ i ] = a [ i − 1 ] a[i] = a[i-1] a[i]=a[i1]
  • 选择两个下标使得 a [ i ] = a [ j ] a[i]=a[j] a[i]=a[j]

询问最小次数使得 ∑ i = 1 n a [ i ] < = k \sum_{i=1}^na[i] <=k i=1na[i]<=k

思路

根据贪心的思想,我们肯定是 将最小的那个减到一定小的时候 ,然后再复制给其他

的数。

在不考虑选哪一个操作的情况下 , 显然都是可以优化 s u m sum sum

因此答案是满足单调的

因此我们可以使用二分进行枚举操作次数

区间 l = 1 , r = n − 1 + m i n ( a [ ] ) l=1,r=n-1+min(a[]) l=1,r=n1+min(a[]),最后在暴力 c h e c k check check即可

Mycode

const int N  = 2e5+10;
int a[N];
ll sum,k;
int n;
bool check(int c){
	ll sum = 0;
	for(int i =  0; i<=min(n-1,c);i++){
		sum+=a[i];
		if(sum - 1ll*(a[n] -c+i)*i + c - i >= k)
		return 1;
	}
	return 0;
}

void solve()
{
	
	cin>>n>>k;
	sum =0  ;
	
	for(int i=1;i<=n;i++){
		cin>>a[i];
		sum+=a[i];
	}
	k = sum - k ;
	if(k<= 0){
		cout<<0<<endl;
		return;
	}

	sort(a+1,a+1+n,greater<int>());
	int l = 1, r = n-1+a[n];
	while(l <= r){
		int mid = l+r>>1;
		if(check(mid)) 
		r = mid - 1;
		else 
		l = mid + 1;
	}
	
	cout<<l<<endl;
	
	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值