xjtuoj 1002:说服合伙人

题目来源

看了别人的代码才知道咋做自己傻乎乎的套了两个结构体按ab不同排序来取最大值做到发现RE了贪心也错了
对于csf来说,永远都是取当前卡片中a最大的那一个,其次是b最大。
因此对于cyy来说,并不需要按b来先取自己最大的,而是轮到自己回合时按a的大小顺序取牌,等到csf取牌时与自己手中最小的b进行比较。大则交换,小则pass。

原因 假设cyy按a的顺序取了第x张牌,发现之后某个csf的回合取的牌的b点数比这一张牌大(如第xk张牌),那么就可以回溯到第x次取牌优先取这一张xk,这样csf就会取第x张牌,之后的取牌顺序照旧。这样就不影响其他时候的决策

但是每次取完牌都需要一次排序找到最小的b进行比较,直接用sort排序复杂度会到$n^2logn$
因此引入小顶堆优先队列来处理cyy的取牌顺序
需要注意的是csf先取牌所以需要考虑当前队列是否为空或者干脆从第二个数开始判断起

贪心(?)+优先队列题

代码
#include<bits/stdc++.h>
#define F(i,n,m) for(int i=n;i<m;i++)
typedef unsigned long long ull;
typedef long long ll;
using namespace std;
struct card {
	ll a,b;
} cs[100005];
bool csf(card aa,card bb) {
	if(aa.a==bb.a) return aa.b>bb.b;
	return aa.a>bb.a;
}
priority_queue<int, vector<int>, greater<int> > q;
//连续>>中间最好有个空格,c++11之后才支持这种格式的出现,防止意外吧
//之前编译一直报错才发现放在std前面了,难怪提示未定义
int main() {
	std::ios::sync_with_stdio(false);
	int n;
	cin>>n;
	F(i,0,n) {
		cin>>cs[i].a>>cs[i].b;
	}
	sort(cs,cs+n,csf);
	ll ans=0;
	F(i,1,n){//第一个csf必先选
		if(i%2){//如果轮到自己选牌
			q.push(cs[i].b);//先选一张塞进去自动排序
			ans+=cs[i].b; 
		} 
		else{
			if(q.top()<cs[i].b){//如果轮到csf的回合发现选这张更适合
				ans-=q.top();
				ans+=cs[i].b;
				q.pop();
				q.push(cs[i].b);
			}
		}
	}
	cout<<ans;
	return 0;
}
</details>
posted @ 2022-04-06 21:42  FPICZEIT  阅读(19)  评论(0编辑  收藏  举报