[题解]P7514 [省选联考 2021 A/B 卷] 卡牌游戏

P7514 [省选联考 2021 A/B 卷] 卡牌游戏

极差不是很好处理,考虑将所有的 \(a,b\) 放在一起进行排序。对于排序后的数组,一个合法的答案可以看作删掉了它的一个前缀 \(s\) 和后缀 \(t\),且:

  • 删除的 \(a\) 中元素不能超过 \(m\) 个。
  • 同一张牌最多只能删 \(1\) 次。

此时对答案的贡献为剩余序列两端的差值。

我们发现,随着 \(|s|\) 的增大 \(|t|\) 是不减的,所以可以用双指针来维护。

时间复杂度 \(O(n\log n)\),瓶颈在于排序。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
struct Node{int v,id;bool typ;}a[N<<1];
int n,m,ans=INT_MAX,cnt[N],flip;
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1,x;i<=n;i++) cin>>x,a[i]={x,i,1};
	for(int i=1,x;i<=n;i++) cin>>x,a[n+i]={x,i,0};
	n<<=1,sort(a+1,a+1+n,[](Node a,Node b){return a.v<b.v;});
	int l,r;
	for(r=n;r;r--){//先找|s|=0时的|t|
		if(cnt[a[r].id]||(flip==m&&a[r].typ)) break;
		cnt[a[r].id]++,flip+=a[r].typ;
	}
	for(l=1;l<=n;l++){
		ans=min(ans,a[r].v-a[l].v);
		cnt[a[l].id]++,flip+=a[l].typ;
		while(r<=n&&(cnt[a[l].id]>1||flip>m)){
			r++;
			cnt[a[r].id]--,flip-=a[r].typ;
		}
		if(r>n) break;//|t|=0时仍不合法
	}
	cout<<ans<<"\n";
	return 0;
}
posted @ 2025-10-07 12:49  Sinktank  阅读(16)  评论(0)    收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2025 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.