首页 > 其他分享 >1832D1

1832D1

时间:2023-05-19 16:34:15浏览次数:42  
标签:剩余 int 增加 1832D1 如果 序列 操作

Red-Blue Operations (Easy Version)

题目出处

Problem - D1 - Codeforces

题目大意

给定一个长度为 \(n\) 的序列,每个位置都有一个整数以及一个颜色,颜色最初都是红色。

可以在这个序列上进行操作,第 \(i\) 次操作选定第 \(j\) 个数

如果位置 \(j\) 是红色,该位置的数加 \(i\) ,颜色变为蓝色。

如果位置 \(j\) 是蓝色,该位置的数减 \(i\) ,颜色变为红色。

给定 \(q\) 次独立的询问,每次询问要求通过恰好 \(k\) 次操作最大化序列中的最小值并输出。

知识点、思路

二分,贪心,分类讨论

具体想法、推导

看到 最大化序列中的最小值 可以比较轻易想到二分+验证的方法,即二分答案,然后验证答案是否成立,再缩小答案区间。所以问题就转化成了如何验证答案是否成立。

考虑到一个数在进行一次加操作后、下次若对它操作一定是减操作,并且由于操作编号的递增,减小的值比增加的值还要大。所以可以想到,对于需要增加一些值的数,可以让对它的增加操作尽可能靠后,如果有 \(r\) 个数需要增加,我们可以算出它们离目标值的距离并排序,并且用最后 \(r\) 次操作依次给它们增加一些值。

如果可以通过这种方法使得所有数都满足条件,那么还需要考虑剩余的操作是否能被成功地消耗掉,从而不会影响最后的过程。

如果没有剩余操作,那么显然成功。

如果序列中每个数都需要增加的情况:

1.如果剩余操作为奇数,那么可以发现至少有一个数需要被减小,一定不成功

2.如果剩余操作为偶数,计为 \(u\) ,那么序列就需要先减少 \(u/2\) 再增加。只需要判断是否有多余的 \(u/2\) 供序列先减少。

如果序列中存在高于目标值的数:

1.如果剩余操作数为奇数,那么使这个值也增加就一定成功

2.如果剩余操作数为偶数,计为 \(u\) ,如果高于目标数的数大于等于二,那么将这两个值都通过奇数次操作增加即可。如果只有一个高于目标数的数,需要判断是否有多余的 \(u/2\) 供序列先减少。

示例代码

bool check(ll x,ll k){
	ll cnt=0,op=0,better=0;
	vector<ll> need;
	need.pb(0);
	for (int i=1;i<=n;i++){
		if (a[i]<x){
			need.pb(x-a[i]);
			cnt++;
		}
		else op=a[i]-x;
	}
	if (k<cnt) return false;
	ll r=k-cnt;
	sort(need.begin(),need.end());
	for (int i=1;i<=cnt;i++){
		if (i+k-cnt<need[i]) return false;
		better+=i+k-cnt-need[i];
	}
	if (r==0) return true;
	if (n==cnt) {
		if (r%2==1) return false;
		if (better<r/2) return false;
		return true;
	}
	if (r%2==1) return true;
	if (n-cnt==1){
		return op+better-r/2>=0;
	}
	return true;
}
 
void solve()
{	
	cin>>n>>q;
 
	for (int i=1;i<=n;i++) cin>>a[i];
	for (int i=1;i<=q;i++) cin>>b[i];
 
	for (int i=1;i<=q;i++){
		ll k=b[i];
 
		ll l=-1e9,r=2e9;
 
		while (l<r){
			ll mid=(l+r+1)/2;
			if (check(mid,k)) l=mid;
			else r=mid-1;
		}
		
		cout<<l<<' ';
	}
	cout<<endl;
}

标签:剩余,int,增加,1832D1,如果,序列,操作
From: https://www.cnblogs.com/xiaosunsun/p/17415565.html

相关文章