Codeforces Round #503 (by SIS, Div. 2)C. Elections政党选举 (枚举答案,贪心)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_30358129/article/details/81624617

题目链接
题意:
告诉你有n个选民,m个党派,其中输入数据会告诉你每个人它选了哪个党派,并且他改变主意需要花多少钱。
你的任务是确保1号党派赢的前提下使用的钱最少,问最少花多少钱

1<=n,m<=3000
注意到党派和选民的数量比较少,而且不好直接求最少花费。
转化为验证答案合法性,但是枚举/二分花费的话也不好验证,改为枚举获胜时的选票数。(注意,不能二分选票,因为不满足单调性)
如果某党的选派大于等于该答案,那么一定需要花钱买该党的票,最后买完票后,如果1党的选票还是少于枚举的值,那么再继续买票。

线上做题时考虑的是开m个优先队列,分别购买m个党派的选票花费,然后就写炸了,一个小时都没搞出来。
看题解发现,可以遍历每个选民,如果该选民所选的党派的选票大于枚举的答案,那么购买该选民的票。这样考虑的话只需要把选民按照收买花费排序一下就行了。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 4000;
struct node{
    int v,cost;
    bool operator <(node b)const{
        return cost<b.cost;
    }
}p[N];
int main(){
   // freopen("a.txt","r",stdin);
    ios::sync_with_stdio(0);
    int n,i,j,m,now = 0;
    cin>>n>>m;
    for(i = 1;i <= n;i ++){
        cin>>p[i].v>>p[i].cost;
        if(p[i].v==1)now ++;
    }
    sort(p+1,p+n+1);
    ll minn = 9e18;
    for(i = now;i <= n/2+1;i ++){
        int num[N];
        bool flag[N];
        memset(num,0,sizeof(num));
        memset(flag,0,sizeof(flag));
        ll cost=0;
        for(j = 1;j <= n;j ++){
            num[p[j].v]++;
            if(p[j].v==1) flag[j] = 1;
        }
        for(j = 1;j <= n;j ++){
            if(num[p[j].v]>=i&&p[j].v!=1) {
                cost += p[j].cost;
                num[p[j].v]--;
                num[1] ++;
                flag[j] = 1;
            }
        }
        for(j = 1;j <= n;j ++){
            if(num[1]>=i)break;
            if(!flag[j]){
                cost += p[j].cost;
                num[1] ++;
                flag[j] = 1;
            }
        }
        minn = min(minn,cost);
    }
    if(minn==9e18)minn = 0;
    cout<<minn;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_30358129/article/details/81624617