现在你要竞选一个县的县长。你去对每一个选民进行了调查。你已经知道每一个人要选的人是谁,以及要花多少钱才能让这个人选你。现在你想要花最少的钱使得你当上县长。你当选的条件是你的票数比任何一个其它候选人的多(严格的多,不能和他们中最多的相等)。请计算一下最少要花多少钱。
Input
单组测试数据。
第一行有一个整数n (1 ≤ n ≤ 10^5),表示这个县的选民数目。
接下来有n行,每一行有两个整数ai 和 bi (0 ≤ ai ≤ 10^5; 0 ≤ bi ≤ 10^4),表示第i个选民选的是第ai号候选人,想要让他选择自己就要花bi的钱。你是0号候选人(所以,如果一个选民选你的话ai就是0,这个时候bi也肯定是0)。
Output
输出一个整数表示花费的最少的钱。
Input示例
5
1 2
1 2
1 2
2 1
0 0
Output示例
3
题解
逆向思维,考虑每个人都投自己,删去钱最多的票。
枚举其他候选人的得票数,显然贪心选取每个人代价最大的票,把这些票加入线段树,假设还需要k票,就从线段树中找最小的k个。
代码
#include<bits/stdc++.h>
#define mod 998244353
#define ll long long
#define inf 0x7fffffff
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int NUM[40005],SUM[40005];
int n,N,mx,M,ans;
vector<int>f[100005];
vector<int>F[100005];
void update(int k,int l,int r,int x)
{
NUM[k]++;SUM[k]+=x;
if (l==r)return;
int mid=(l+r)>>1;
if (x<=mid) update(k<<1,l,mid,x);
else update(k<<1|1,mid+1,r,x);
}
int query(int k,int l,int r,int x)
{
if (l==r) return x*l;
if (NUM[k]==x) return SUM[k];
int mid=(l+r)>>1;
if (NUM[k<<1]>=x) return query(k<<1,l,mid,x);
else return SUM[k<<1]+query(k<<1|1,mid+1,r,x-NUM[k<<1]);
}
int main()
{
n=read();
for (int i=1;i<=n;i++)
{
int a=read(),b=read();
if (b==0) continue;
ans+=b;
N=max(a,N);
mx=max(mx,b);
f[a].push_back(b);
}
for (int i=0;i<=N;i++)
{
if (!f[i].size()) continue;
sort(f[i].begin(),f[i].end(),greater<int>());
M=max((int)f[i].size(),M);
for (int j=0;j<f[i].size();j++)
F[j].push_back(f[i][j]);
}
int sum=ans;
for (int i=0;i<M;i++)
{
n-=F[i].size();
for (int j=0;j<F[i].size();j++)
{
update(1,1,mx,F[i][j]);
sum-=F[i][j];
}
int tmp=0;
if (n<=i+1) tmp=query(1,1,mx,i+2-n);
ans=min(ans,sum+tmp);
}
printf("%d",ans);
return 0;
}