牛客练习赛83 C.集合操作(二分,单调性)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客练习赛83 C.集合操作(二分,单调性)相关的知识,希望对你有一定的参考价值。

LINK

每次把最大的数字减去 p p p,显然随着 k k k的增大,集合的最大值是单调不增的

所以我们可以二分最大值 m i d mid mid

计算把所有数操作到小于等于 m i d mid mid需要的操作次数 f f f

不过这样可能无法精确的计算到 f = k f=k f=k的时候

因为可能存在多个数值相等,导致随着最大值变化操作次数突变

那么就二分到 f f f小于等于 k k k但最接近 k k k的时候

可以证明 f f f k k k的差值不会多于 n − 1 n-1 n1

因为如果差值为 n n n,那么所有数可以整体减去 p p p,显然这不是最优的 f f f

之后暴力操作即可

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 1e6+10;
int a[maxn],k,p,n;
int isok(int mid)
{
	int now = 0;
	for(int i=1;i<=n;i++)
	{ 
		if( a[i]<=mid )	continue;
		int x = ( a[i]-mid )/p+(( a[i]-mid )%p!=0);
		now += x;
		if( now>k )	return false;
	}
	return true;
}
signed main()
{
	scanf("%lld%lld%lld",&n,&k,&p );
	for(int i=1;i<=n;i++)	scanf("%lld",&a[i] );
	if( p==0 || k==0 )
	{
		sort( a+1,a+1+n );
		for(int i=1;i<=n;i++)		printf("%lld ",a[i] );
		return 0;
	}
	int l = LLONG_MIN, r = LLONG_MAX, ans = 0;
	while( r>=l )
	{
		int mid = l+r>>1;//令最大值小于等于mid 
		if( isok(mid) )	r = mid-1, ans = mid;
		else	l = mid+1;
	}
	for(int i=1;i<=n;i++)
	{
		if( a[i]<=ans )	continue;
		int x = ( a[i]-ans )/p+(( a[i]-ans )%p!=0);
		a[i] -= x*p; k -= x;
	}
	for(int i=1;i<=n;i++)
		if( k&&a[i]==ans )	a[i] -= p, k--;
	sort( a+1,a+1+n );
	for(int i=1;i<=n;i++)	printf("%lld ",a[i] );
}

以上是关于牛客练习赛83 C.集合操作(二分,单调性)的主要内容,如果未能解决你的问题,请参考以下文章

决策单调性优化dp 专题练习

牛客练习赛54 C.排序 暴力枚举+逆序对

牛客网Nowcoder 牛客练习赛13 A.幸运数字Ⅰ B.幸运数字Ⅱ(数组或者dfs) C.幸运数字Ⅲ(思维)

Move (牛客多校) (诈骗二分,诈骗复杂度)

牛客练习赛83 E.牛客推荐系统开发之标签重复度

牛客练习赛84 C.牛客推荐系统开发之选飞行棋子(状态dp)