专栏文章

题解:AT_abc388_e [ABC388E] Simultaneous Kagamimochi

AT_abc388_e题解参与者 7已保存评论 7

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
7 条
当前快照
1 份
快照标识符
@miqjacrt
此快照首次捕获于
2025/12/04 05:43
3 个月前
此快照最后确认于
2025/12/04 05:43
3 个月前
查看原文
有点小题大做的感觉,本题我们使用反悔贪心解决。
反悔贪心的一般策略大概可以概括为:能对答案产生贡献的方案就直接选下来,否则,我们找一下前面选过的最不优的方案进行更换。
那本题我们也可以这样。不妨开两个优先队列,一个 q1q1 存放已选方案,一个 q2q2 存放未选用的数,请注意 q1q1 存放的是一个二元组,以较大数为关键字从小到大排序。
先排序。然后往后面扫。设当前扫到的是 nownow
  1. 如果 q2q2 中的最小数 toptop 可以与之搭配,即满足 top×2nowtop\times 2\le now,那么搭配,将二元组 (top,now)(top,now) 存进 q1q1。答案加一。
  2. 若不能,取出 q1q1 的队头 (x,y)(x,y),改为 (x,now)(x,now)。然后把 yy 弹入 q2q2。这一步的操作可以理解为,把较小的 yy 取出来,以便后面和其他的数配对。
  3. 如果上述两种均不满足,那就直接将 nownow 弹入 q2q2
那么完成了。时间复杂度是 O(nlogn)O(n\log n)
请注意,由于优先队列存放 pair 时以第一个数为关键字,所以我们把二元组对调即可。
CPP
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6+10;
int a[N],n,ans;
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i = 1;i<=n;i++)
		cin>>a[i];
	sort(a+1,a+n+1);
	priority_queue<pair<int,int>,vector<pair<int,int> > ,greater<pair<int,int> > > q1;
	priority_queue<int,vector<int>,greater<int> > q2;
	for(int i = 1;i<=n;i++){
		if(!q2.empty() && q2.top()*2 <= a[i]){
			ans++;
			q1.push(make_pair(a[i],q2.top()));
			q2.pop();
		}
		else if(!q1.empty() && q1.top().first < a[i]){
			pair<int,int> f = q1.top();
			q1.pop();
			q2.push(f.first);
			q1.push(make_pair(a[i],f.second));
		}
		else q2.push(a[i]);
	}
	cout<<ans<<endl;
	return 0;
}

评论

7 条评论,欢迎与作者交流。

正在加载评论...