解题思路
我们可以先二分答案每个人的最小的 。
然后对于每一个 ,我们对其判断是否能符合题意。
判断过程:
我们可以使用贪心思想,将被第 个人选取的 个选票除外的剩余选票,尽量分给原有投票数量大的人,看看加上这些剩余的选票之后,能不能有 个人大于第 个人的选票。
首先可以将每个人的初始票数 从小到大排个序;
找出第一个比 大的数的前一个位置 ;
那我们选取票数尽量大的(也就是 到 );
那么我们要分情况讨论:
1. 不在 中,
如果 ,也就是已经有 个人票数比他大了,直接返回 false;
否则,我们可以知道 这段中是比 要小的,那我们维护一个后缀和来求区间和,将 的区间和加上剩余票数,与 比较即可。
2. 在 中,
由于 在里面,所以多取一个,变成 ;
过程跟上面差不多,但是算 区间和时要把 减掉就行。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,k,s;
int a[200001],b[200001];
int sum[200001];
bool check(int x,int wz)
{
int temp=a[wz]+x;
int rest=k-s-x;
int pos=upper_bound(b+1,b+n+1,temp)-b-1;
if(a[wz]<b[n-m+1])
{
if(pos<n-m+1)return 0;
if(sum[n-m+1]-sum[pos+1]+rest>=(pos-(n-m))*(temp+1))return 0;
else return 1;
}
else{
if(pos<n-m)return 0;
if(sum[n-m]-sum[pos+1]+rest-a[wz]>=(pos-(n-m))*(temp+1))return 0;
return 1;
}
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
{
cin>>a[i];
s+=a[i];
b[i]=a[i];
}
if(n==1)
{
cout<<0;
return 0;
}
if(n==m)
{
for(int i=1;i<=n;i++)
{
cout<<0<<" ";
}
return 0;
}
sort(b+1,b+n+1);
sum[n]=b[n];
for(int i=n-1;i>=1;i--)
{
sum[i]=sum[i+1]+b[i];
}
int l,r,mid,ans;
for(int i=1;i<=n;i++)
{
l=0,r=k-s,ans=-1;
while(l<=r)
{
mid=(l+r)>>1;
if(check(mid,i))
{
ans=mid;
r=mid-1;
}
else
{
l=mid+1;
}
}
cout<<ans<<" ";
}
}