Atcoder B - Voting Judges(构造 + 二分)

题意:
有n个人,m个评委,每个评委可以选 v v v个人,分数前 p p p名可以被选,问可能被选的人数有多少。
思路:
对分数从大到小排个序,可以肯定的是分数较小的被选,那么分数比它大的也肯定被选,所以我们可以二分答案,进行判断。
对于每个 m i d mid mid我们肯定 + m +m +m,然后对 1 到 p − 1 1到p-1 1p1 p + 1 到 p+1到 p+1 n n n m m m肯定不会影响 a [ m i d ] a[mid] a[mid] a [ p ] a[p] a[p]比较,然后如果还剩余的话,对 p 到 m i d − 1 p到mid-1 pmid1进行分配,如果这个数大于 a [ m i d ] + m a[mid] + m a[mid]+m,那肯定不满足,如果小于的话,我们贪心的尽量多的给他分配,即 a [ m i d ] + m − a [ i ] a[mid]+m-a[i] a[mid]+ma[i],若分配完后,还有剩余那肯定不满足。


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define ll long long
const int N = 1e5 +5;
ll a[N];
ll b[N];
bool ok(ll x,ll m,ll v,ll p,ll n){
     

    memcpy(b,a,sizeof a);
    for(int i = x;i <= n;++i){
     
        if(!v) break;
        b[i] += m;
        v --;
    }
    for(int i = 1;i <= p-1;++i){
     
        if(!v) break;
        b[i] += m;
        v --;
    }
    ll d = v * m;
    if(d == 0){
     
        return b[x] >= b[p];
    }
    else{
     
        for(int i = p;i < x;++i){
     
            if(b[i] - b[x] > 0) return 0;
            ll po = b[x] - b[i];
            po = min(po,m);
            d -= po;
            if(d <= 0) break;
        }
        if(d > 0) return 0;
        return 1;
    }
}
int main()
{
     
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
	ll n,m,v,p;
	cin >> n >> m >> v>>p;
	for(int i = 1;i <= n;++i){
     
		cin >> a[i];
	}
    sort(a + 1,a + n + 1,greater<ll>());
    int l = p ,r = n;
    while(l < r){
     
        int mid = l + r + 1 >> 1;
        if(ok(mid,m,v,p,n)) l = mid;
        else r = mid - 1;
    }
    cout<<l;
			
    return 0;


}

你可能感兴趣的:(二分三分)