这个题直接考虑:每种长度的桌脚,分别作为最长的桌脚的情况。根据这个枚举。
对于最长桌脚x,所以大于x的长度肯定必须要砍掉。
对于小于x的桌脚,尽量多地保留x(尽量少地砍x),其实就是不砍。
然后看<x长度的桌脚,设至少需要砍掉k个。把这些<x的长度的,从小到大排序,前k个的合就是需要砍掉的。
CF上的原题比这个简单,主要是因为CF上那个,花费只有200以内,所以可以开桶。
但是51nod这个题长度有100000,所以不能扫描桶了。
所以这里我使用一个Treap 每次算出前k小的代价和。
时间复杂度O(nlgn)
#include<iostream>
#include<string.h>
#include<string>
#include<algorithm>
#include<stdio.h>
#include<vector>
#include<time.h>
#define LL long long int
using namespace std;
LL SUM = 0;
struct node
{
int pri;
LL key;
LL sum;
LL size;
node *ch[2];
int cmp(LL x)
{
if(x<=key) return 0;
else return 1;
}
void maintain()
{
int s=1;
if(ch[0]!=NULL) s+=ch[0]->size;
if(ch[1]!=NULL) s+=ch[1]->size;
size=s;
LL ms = key;
if(ch[0]!=NULL) ms += ch[0]->sum;
if(ch[1]!=NULL) ms += ch[1]->sum;
sum = ms;
}
node()
{
ch[0]=ch[1]=NULL;
sum = 0;
}
};
struct Treap
{
node *head;
int NUM;
void rotate(node *&p,int d)
{
node *save=p->ch[d];
node *temp=save->ch[d^1];
p->ch[d]=temp;
p->maintain();
save->ch[d^1]=p;
p=save;
p->maintain();
}
void insert(node *&p,LL x)
{
if(p==NULL)
{
p=new node();
p->pri=rand();
p->key=x;
p->sum = x;
p->size=1;
return;
}
int d=p->cmp(x);
insert(p->ch[d],x);
if(p->pri < p->ch[d]->pri)
{
rotate(p,d);
}
if(p!=NULL) p->maintain();
}
bool find(int x)
{
node *p=head;
while(p!=NULL)
{
if(p->key==x) return true;
int d=p->cmp(x);
p=p->ch[d];
}
return false;
}
void remove(node *&p,int x)
{
int cp=p->cmp(x);
if(p->key==x)
{
if(p->ch[0]==NULL) p=p->ch[1];
else if(p->ch[1]==NULL) p=p->ch[0];
else
{
//把优先级高的转上来
int d=(p->ch[0]->pri > p->ch[1]->pri ? 0:1);
rotate(p,d);
remove(p->ch[d^1],x);
}
}
else remove(p->ch[cp],x);
if(p!=NULL) p->maintain();
}
void revise(int x,int to)
{
if(find(x)==false) return;
else
{
remove(head,x);
insert(head,to);
}
}
LL gk(node *p,int k)//
{
//cout<<p->sum<<endl;
int sum=1;
LL ss = 0;
if(p->ch[0]!=NULL) sum+=p->ch[0]->size;
if(sum==k)
{
LL tmp = p->key;
if(p->ch[0]!=NULL) tmp += p->ch[0]->sum;
SUM += tmp;
return tmp;
}
else if(sum<k)
{
if(p->ch[0] != NULL)
{
SUM += p->ch[0]->sum;
}
SUM += p->key;
return gk(p->ch[1],k-sum);
}
else return gk(p->ch[0],k);
}
void del(node *&p)
{
if(p==NULL) return;
del(p->ch[0]);
del(p->ch[1]);
delete p;
p=NULL;
}
Treap()
{
head=NULL;
NUM=0;
}
//以上是公共部分,注意NUM的更新
void traverse(node *p)
{
if(p==NULL) return;
printf("%d\n",p->key);
traverse(p->ch[0]);
traverse(p->ch[1]);
}
};
Treap tree;
const int maxn = 120000;
vector<LL> length[maxn];
LL cnt[maxn];
int n;
int f[maxn];
void init()
{
tree.del(tree.head);
memset(length,0,sizeof(length));
}
int main()
{
while(cin>>n)
{
init();
LL sum = 0;
for(int i = 1;i<=n;i++)
{
scanf("%d",&f[i]);
}
for(int i = 1;i<=n;i++)
{
LL tmp;
scanf("%d",&tmp);
length[f[i]].push_back((LL)tmp);
sum += (LL)tmp;
}
LL ans = 10000000000000000;
LL now = 0;
for(int i = 1;i<=100000;i++)
{
if(length[i].size() == 0) continue;
int x = length[i].size();
for(int j = 0;j<length[i].size();j++) sum -= length[i][j];
if(x > now)
{
ans = min(ans,sum);
}
else
{
SUM = 0;
LL tmp = tree.gk(tree.head,now - x + 1);
//if(SUM<0) cout<<i<<" "<<SUM<<endl;
//cout<<SUM<<endl;
ans = min(ans,sum + SUM);
}
for(int j = 0;j<length[i].size();j++)
{
LL v = (LL)length[i][j];
tree.insert(tree.head,v);
now ++;
}
}
cout<<ans<<endl;
}
return 0;
}