直接做不太可做,我们可以枚举一个
d
表示其他人最大值不大于
从大到小枚举
d
<script type="math/tex" id="MathJax-Element-20">d</script> 即可。
#include<cstdio>
#include<vector>
#include<algorithm>
#define Fir first
#define Sec second
#define mp(x,y) make_pair(x,y)
using namespace std;
const int maxn=100005;
vector<int> a[maxn];
pair<int,int> b[maxn];
int n,m,all;
bool _cmp(const int &x,const int &y){ return x>y; }
int res,ans;
struct node{
int cnt,sum; node* ch[2];
node(){ cnt=sum=0; ch[0]=ch[1]=0; }
void maintain(){
cnt=ch[0]->cnt+ch[1]->cnt;
sum=ch[0]->sum+ch[1]->sum;
}
} *root;
typedef node* P_node;
P_node Build(int L,int R){
P_node p=new node();
if(L==R) return p;
int mid=(L+R)>>1;
p->ch[0]=Build(L,mid); p->ch[1]=Build(mid+1,R);
return p;
}
void Updata(P_node p,int L,int R,int pos,int k){
if(R<pos||pos<L) return;
if(L==R){ p->cnt+=k; p->sum+=L*k; return; }
int mid=(L+R)>>1;
Updata(p->ch[0],L,mid,pos,k); Updata(p->ch[1],mid+1,R,pos,k);
p->maintain();
}
int Query(P_node p,int L,int R,int k){
if(L==R) return L*k;
int mid=(L+R)>>1;
if(p->ch[0]->cnt>=k) return Query(p->ch[0],L,mid,k);
return p->ch[0]->sum+Query(p->ch[1],mid+1,R,k-p->ch[0]->cnt);
}
int main(){
freopen("51nod1494.in","r",stdin);
freopen("51nod1494.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++){
int x,y; scanf("%d%d",&x,&y);
a[x].push_back(y);
}
root=Build(0,10000);
all=a[0].size();
for(int i=1;i<=100000;i++){
sort(a[i].begin(),a[i].end(),_cmp);
for(int j : a[i]) Updata(root,0,10000,j,1);
b[++m]=mp(-a[i].size(),i);
}
sort(b+1,b+1+m);
ans=2e9;
for(int d=n;d>=0;d--){
for(int i=1;i<=m;i++){
if(a[b[i].Sec].size()<=d) break;
while(a[b[i].Sec].size()>d){
int t=*a[b[i].Sec].rbegin(); a[b[i].Sec].pop_back();
res+=t; all++; Updata(root,0,10000,t,-1);
}
}
if(all>d){ ans=min(ans,res); break; }
if(d+1-all<=root->cnt) ans=min(ans,res+Query(root,0,10000,d+1-all));
}
printf("%lld\n",ans);
return 0;
}