[P6093 [JSOI2015] 套娃]题解-贪心+set

发布时间 2023-07-07 16:08:34作者: H_W_Y

20230707
不想做题于是随机跳题
传送门

我们考虑每个套娃\(i\)套到另一个套娃\(j\)里面的价值
很明显可以知道,这样可以减少\(b[j]* out[i]\)
为了让答案尽可能小
我们就要让每一个套娃被套进去的价值最大
而我们并不能改变\(out[i]\)
所以只要把它套到最大的\(b[j]\)中即可

再来换一个角度,考虑对于每一个\(j\)
我们想要找到能被我套进去的\(out[i]\)最大的\(i\)

为了同时满足这两个条件
首先我们按照\(b\)的大小从大到小排序
每一次再去找小于\(in[i]\)的最大的\(out[j]\)
\(ans\)减去这种操作带来的贡献\(ou[j]* b[i]\)即可
而维护是可以用set来进行

#include <bits/stdc++.h>
using namespace std;
#define ll long long

const int maxn=2e5+10;
int n;
ll ans=0;
struct node{
  int out,in,b;
  bool operator < (const node &rhs)const{
  	if(b!=rhs.b) return b>rhs.b;
  	return out>rhs.out;
  }
}a[maxn];

multiset<int> st;
int read(){
  int x=0,f=1;char ch=getchar();
  while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
  while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}

int main(){
  /*2023.7.7 H_W_Y P6093 [JSOI2015] 套娃 贪心+set*/ 
  n=read();
  for(int i=1;i<=n;i++){
  	a[i].out=read();a[i].in=read();a[i].b=read();
  	st.insert(a[i].out);ans+=1ll*a[i].in*a[i].b;
  }
  sort(a+1,a+n+1);
  for(int i=1;i<=n;i++){
  	multiset<int>::iterator it=st.lower_bound(a[i].in);
  	if(it!=st.begin()) ans-=1ll* (*--it)*a[i].b,st.erase(it);
  }
  printf("%lld\n",ans);
  return 0;
}

总结:
在贪心算法中经常会需要出现类似找出并删除最小的大于等于某个值的元素
这种操作能轻松地通过 set 来完成。