codeforces#1251E2. Voting (Hard Version)(贪心)

题目链接:

http://codeforces.com/contest/1251/problem/E2

题意:

主角需要获得n个人的投票

有两种方式让某个人投票

1,已经投票的人数大于m

2,花p枚硬币收买

数据范围:

$1leq n leq 200 000$

分析: 

对$m$进行排序

保留前缀的$m$数组,$pre[x]$为$m$小于等于$x$的人数

对x逆序处理,当枚举到$x$的时候,假设$m$小于等于$x-1$的那些人已经投票,也就是有$pre[x-1]$人已经投票

如果$pre[x-1]>=x$那么不需要处理

如果$pre[x-1]<x$那么$m$在$x$到$n$的人至少要收买$x-pre[x-1]$个人

得到所有$x$需要收买的后缀,显然,从后往前处理最优

AC代码:

#include <bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
using namespace std;
const int maxn=2e5+7;
int pre[maxn];
vector<int>ve[maxn];
multiset<int>se;
int main() {
    int T,n;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            int a,b;
            scanf("%d %d",&a,&b);
            pre[a]++;
            ve[a].push_back(b);
        }
        for(int i=1;i<=n;i++)
            pre[i]+=pre[i-1];
        int cnt=0;
        ll ans=0;
        for(int i=n;i>=1;i--){
            for(int j=0;j<ve[i].size();j++)se.insert(ve[i][j]);
            int v=i-cnt-pre[i-1];
            while(v>0){
                ans+=(*se.begin());
                se.erase(se.begin());
                v--;
                cnt++;
            }
        }
        se.clear();
        for(int i=0;i<=n;i++)ve[i].clear(),pre[i]=0;
        printf("%lld
",ans);
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/carcar/p/11761552.html