codeforces 1019 A. Elections (枚举或三分)

链接

这里写图片描述

昨天CF的题,没想到自己会做的这么傻逼。。。真菜啊

题意:就N个选民,M个政党。已知每个选民原本打算投给的政党,已经收买他们的价格,问你花费最少的价格,使得1号政党的票数最多。

思路:直接考虑政党的得票数,使得1号政党高于这个票数,其他政党低于这个票数就行了。(1号政党可以远远高于这个得票数,但其他政党必须低于这个票数)然后从1到N枚举这个票数,维护最小值就行了。只要统计每个政党的得票数,那数据按收买价格从小到大排序就行了,对于高于这个票数的政党,就直接收买选民,知道不高于为止,如果到最后1号政党的票数还是低于枚举的票数,那么就从小到大再扫描一遍,只有是没被收买的都收买掉,直到达到为止。

这是O(N^2)的做法,不过我们可以考虑这样一件事,最小值一定出现在[1,N]这个区间,所如果画出花费金额和枚举的得票数就会发现这是一个凹函数,存在极小值。
这里写图片描述

所以我们可以三分求一下这个凹函数的极小值。
不理解三分的可以看下这个博客:https://blog.csdn.net/qq_34374664/article/details/70141246

这样我们就可以把时间复杂度降为O(NlogN)的了。

枚举代码如下:

#include<bits/stdc++.h>

using namespace std;
const int MAX = 3010;
typedef long long ll;
int N,M;
class Node{
public:
    int p;
    ll c;
};
Node q[MAX];
bool operator < (Node A,Node B){
    return A.c < B.c;
}
int num[MAX],now[MAX];
bool book[MAX];
ll check(int Max){
    for(int i=1;i<=M;++i)   now[i] = num[i];
    memset(book,false,sizeof(book));
    ll sum = 0;
    for(int i=1;i<=N;++i){
        if(q[i].p == 1){
            book[i] = true;
        }
        else if(now[q[i].p] < Max)   continue;
        else{
            now[q[i].p]--;
            sum += q[i].c;
            now[1]++;
            book[i] = true;
        }
    }
    if(now[1] < Max){
        for(int i=1;i<=N;++i){
            if(now[1] == Max)   break;
            if(!book[i]){
                sum += q[i].c;
                now[1]++;
                book[i] = true;
            }
        }
    }
    return sum;
}
int main(void){
    cin >> N >> M;
    for(int i=1;i<=N;++i){
        cin >> q[i].p >> q[i].c;
        num[q[i].p]++;
    }
    sort(q+1,q+1+N);
    ll res = check(1);
    for(int i=1;i<=N;++i){
        res = min(check(i),res);
      //  cout << check(i) << endl;
    }
    cout << res << endl;
    return 0;
}

三分做法如下:

#include<bits/stdc++.h>

using namespace std;
const int MAX = 3010;
typedef long long ll;
int N,M;
class Node{
public:
    int p;
    ll c;
};
Node q[MAX];
bool operator < (Node A,Node B){
    return A.c < B.c;
}
int num[MAX],now[MAX];
bool book[MAX];
ll check(int Max){
    for(int i=1;i<=M;++i)   now[i] = num[i];
    memset(book,false,sizeof(book));
    ll sum = 0;
    for(int i=1;i<=N;++i){
        if(q[i].p == 1){
            book[i] = true;
        }
        else if(now[q[i].p] < Max)   continue;
        else{
            now[q[i].p]--;
            sum += q[i].c;
            now[1]++;
            book[i] = true;
        }
    }
    //如果一号政党还没达到要求的票数,就从小到大开始寻找,没被收买的一律收买
    if(now[1] < Max){
        for(int i=1;i<=N;++i){
            if(now[1] == Max)   break;
            if(!book[i]){
                sum += q[i].c;
                now[1]++;
                book[i] = true;
            }
        }
    }
    return sum;
}
int main(void){
    cin >> N >> M;
    for(int i=1;i<=N;++i){
        cin >> q[i].p >> q[i].c;
        num[q[i].p]++;
    }
    sort(q+1,q+1+N);
    int l = 1,r = N;
    while(r - l > 3){
        int mid = (l+r)/2;
        int rmid = (mid+r)/2;
        ll sum1 = check(mid);
        ll sum2 = check(rmid);
        if(sum1 > sum2) l = mid;
        else    r = rmid;
    }
    ll res = check(l);
    for(int i=l+1;i<=r;++i){
        res = min(res,check(i));
    }
    cout << res << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhao5502169/article/details/81625471