51NOD - 1461稳定桌

题目链接:51NOD - 1461稳定桌


枚举每一个作为最长的价值。

所以我们从大往小枚举,然后我们就可以算出比当前值大的和,直接变量记录即可。

然后再权值树种找最小的k个值。

所有答案取min即可。


AC代码:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int n,cnt[N],l[N],d[N],num[N<<2],sum[N<<2],vis[N],res=1e18,s[N],now,tmp;
vector<int> v[N];
void change(int p,int l,int r,int x,int v){
	if(l==r){sum[p]+=x*v,num[p]+=v; return ;}
	int mid=l+r>>1;
	if(x<=mid)	change(p<<1,l,mid,x,v);
	else	change(p<<1|1,mid+1,r,x,v);
	sum[p]=sum[p<<1]+sum[p<<1|1],num[p]=num[p<<1]+num[p<<1|1];
}
int ask(int p,int l,int r,int s){
	if(l==r)	return s*l;
	int mid=l+r>>1;
	if(num[p<<1]>=s)	return ask(p<<1,l,mid,s);
	else	return sum[p<<1]+ask(p<<1|1,mid+1,r,s-num[p<<1]);
}
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++)	scanf("%lld",&l[i]);
	for(int i=1;i<=n;i++){
		scanf("%lld",&d[i]),v[l[i]].push_back(d[i]),s[l[i]]+=d[i];
		change(1,1,1e5,d[i],1);	cnt[l[i]]++;
	}	
	now=n;
	for(int i=1e5;i>=1;i--){
		if(!cnt[i])	continue;
		for(auto j:v[i])	change(1,1,1e5,j,-1);
		int need=now-cnt[i]*2+1;
		if(need<=0){res=min(res,tmp);	now-=cnt[i];	continue;}
		res=min(res,tmp+ask(1,1,1e5,need));	now-=cnt[i];	tmp+=s[i];
	}
	cout<<res;
	return 0;
}
发布了809 篇原创文章 · 获赞 246 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/weixin_43826249/article/details/105255550