AtCoder Grand Contest 041 B.Voting Judges (二分)

題目鏈接:https://atcoder.jp/contests/agc041/tasks/agc041_b

題目大意:

有n個問題,m個裁判,每個裁判會給v個不同的問題投票,投一票加一分;同時每個問題還有一個ai作爲初始分數,現在在所有裁判投票完成後,選取前p大的問題,如果a[p]==a[p+1]==a[p+2]這樣的話,相同的分數都會選擇進來,問你有多少個問題可能被選擇?

思路:

比賽時二分寫醜了,改了一下就過了。。。

首先肯定按照初始分數排序,這裏按照從大到小排,每個問題最多被加m分(m個裁判都選擇了這個問題),且最多會有v個問題被加m分。

如果a[i]這個問題可以,那麼分數>a[i]的肯定也可以,所以我們考慮二分答案mid;

如何判斷mid這個位置可不可以被選呢?

  • 如果mid<=p,那麼一定是可以的。
  • 如果a[mid]+m<a[p],不管怎麼加肯定不行,一定是不可以的。
  • 剩下的情況,如果可以被選,那麼我最優的選擇方法肯定是a[1],a[2],a[3]........a[p-1],a[mid]。換句話說,我只需要保證a[mid]在所有加分完成之後比a[p]大就可以了。

現在考慮如何加分是最優的,我們一共有m*v分,首先將m分加給a[mid],然後有如下策略:

  1. 如果我將m分加給a[1],a[2]....a[p-1],並不會影響我與a[p]比較,這樣做可以捨去(p-1)*v分。
  2. 如果我將m分加給a[mid+1],a[mid+2].....a[n],也不會有影響,因爲不管怎麼加,a[mid]+m>=a[mid+1]+m;這樣做可以捨去(n-mid)*v分
  3. 剩下的分,我們平攤給p<=i<mid這些元素,保證每個元素加的分最多爲min(m,a[mid]+m-a[i]),也就是每個元素加分後不能大於a[mid]+m;

這樣加完分之後,如果分數還有剩餘,那說明一定有一個在p之後的元素會加分加到大於a[mid]+m,這種情景不行;否則,mid就是合法的。

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e5+10;
int a[maxn];
int cmp(const int a,const int b){
    return a>b;
}
int n,m,v,p;
int b[maxn];
bool judge(int mid){
    //printf("hello %lld\n",mid);
    if(mid<=p)return true;
    if(a[mid]+m<a[p])return false;
    if(v<=p-1&&a[mid]+m>=a[p])return true;
    for(int i=1;i<=n;i++)b[i]=a[i];
    int temp=0;
    for(int i=1;i<=p-1;i++){
        b[i]+=m;
        temp+=m;
    }
    //給開頭的p-1個元素加值
    int inx=n,cnt=v-p+1;
    //給後面的元素加值
    while(inx>mid&&cnt>1){
        temp+=m;
        inx--;
        cnt--;
        b[inx]+=m;
    }
    temp+=m;
    int now=a[mid]+m;
    int res=m*v-temp;
    //中間還能被填多少
    for(int i=p;i<mid;i++){
        int add=min(m,max(now-a[i],0ll));
        if(add>res)add=res;
        res-=add;
        b[i]+=add;
    }
    return now>=b[p]&&res<=0;
}
signed main(){
    cin>>n>>m>>v>>p;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    sort(a+1,a+n+1,cmp);
    int low=1,high=n;
    int ans=0;
    while(low<=high){
        int mid=(low+high)>>1;
        if(judge(mid)){
            low=mid+1;
            ans=mid;
        }
        else{
            high=mid-1;
        }
    }
    cout<<ans<<endl;
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章