[题解]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;
}