题目链接:
http://codeforces.com/contest/1251/problem/E2
题意:
主角需要获得n个人的投票
有两种方式让某个人投票
1,已经投票的人数大于m
2,花p枚硬币收买
数据范围:
$1\leq 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\n",ans); } return 0; }