练习赛83-C集合操作
首先可以把操作完成后的最大值进行二分
因为显然操作次数越多,最大值越小,存在一个单调性
这时候得到一个操作完成后的最大值max,那么可以把数组进行操作,把所有数变为≤max的形式
此时,k-n<操作次数≤k,所以最后至多只要再操作n-1次,当且仅当数组中所有数都max时还需操作次数n-1次
反证法证明,如果还要操作n次或n次以上,数组最大值必定<max,与上矛盾,故最多再操作n-1次
因此,得到max并把数组进行初步更改后,还剩余一个操作次数k1(k-n<k1≤k),且被再次修正的数必定等于max
#学习路径#
因为显然操作次数越多,最大值越小,存在一个单调性
这时候得到一个操作完成后的最大值max,那么可以把数组进行操作,把所有数变为≤max的形式
此时,k-n<操作次数≤k,所以最后至多只要再操作n-1次,当且仅当数组中所有数都max时还需操作次数n-1次
反证法证明,如果还要操作n次或n次以上,数组最大值必定<max,与上矛盾,故最多再操作n-1次
因此,得到max并把数组进行初步更改后,还剩余一个操作次数k1(k-n<k1≤k),且被再次修正的数必定等于max
直接for一遍进行二次修改,最后sort输出即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[1000005];
ll k,p;
int n;
bool check(ll x){
ll s=0;
for (int i=1;i<=n;i++)
if (a[i]>x){
ll t=(a[i]-x-1)/p+1;
s+=t;
if (s>k)return 0;
}
return 1;
}
int main(){
scanf("%d%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(i==n?"%lld\n":"%lld ",a[i]);
return 0;
}
ll l,r,mid;
r=9223372036854775807;
ll ans=l=-r;
while (l<=r){
mid=(l+r)/2;
if (check(mid))ans=mid,r=mid-1;
else l=mid+1;
}
ll s=0;
// printf("%lld\n",ans);
for (int i=1;i<=n;i++)
if (a[i]>ans){
s=(a[i]-ans-1)/p+1;
a[i]-=s*p;
k-=s;
}
for(int i=1;i<=n&&k;i++)
if(a[i]==ans)a[i]-=p,k--;
sort(a+1,a+1+n);
for (int i=1;i<=n;i++)printf("%lld ",a[i]);
} 