牛客练习赛83 C.集合操作(二分,单调性)
Posted issue是fw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客练习赛83 C.集合操作(二分,单调性)相关的知识,希望对你有一定的参考价值。
每次把最大的数字减去 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 n−1
因为如果差值为 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.集合操作(二分,单调性)的主要内容,如果未能解决你的问题,请参考以下文章