专栏文章
题解:AT_abc403_d [ABC403D] Forbidden Difference
AT_abc403_d题解参与者 4已保存评论 9
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 9 条
- 当前快照
- 1 份
- 快照标识符
- @mipgyxg1
- 此快照首次捕获于
- 2025/12/03 11:50 3 个月前
- 此快照最后确认于
- 2025/12/03 11:50 3 个月前
没有二分的吗,我来一发。
题目传送门
思路
既然是找一个数能不能被删,且限制下标,不是有序的,就不能用二分了?
我们发现 也就是说这个限制对于排序来说没有作用,所以排序。
排完序后就可以直接二分了吗?
因为我们枚举每个数,从这个数开始往后找,我们只需要找到后直接计数器加一,所以删哪个都一样。
至于删去后的数,直接存数组里打标记,否则会导致我下一次遍历到这个数时又给他用了,但他早已被删了。
有个需要注意的地方:
举个例子:
CPP6 3
2 2 2 5 5 5
这个情况下,我能直接二分到这一堆 中间去然后走人吗?这样的话就不好二分了,我们可以往右找,直到没有了或被用了。
还有另一个要注意的地方:
当 的情况,再举个例子:
CPP10 0
1 2 2 3 3 3 4 4 4 4
很明显这里不能都只删一个,所以要判断情况:当前这剩余数量小于两个的时候只删一个;大于两个的时候就每找一次就删两下,直到剩余数量小于两个的时候,这时只删一个。
代码
CPP#include<bits/stdc++.h>
using namespace std;
int n,d,a[200050],cnt=0,vis[2000050],t[2000050];
int main(){
cin>>n>>d;
for(int i = 1 ; i <= n ; i++){
cin>>a[i];
t[a[i]]++;
}
if(n==1){//特判,我也不知道为什么
cout<<0;
return 0;
}
sort(a+1,a+n+1);
for(int i = 1 ; i <= n ; i++){
int l=i,r=n,ret=0;
if(!vis[i]){
while(l<=r){
int mid=(l+r)/2;
if(a[i]-a[mid]==-d&&!vis[mid]){
ret=mid;
l=mid+1;
}
else if(a[i]-a[mid]>-d){
l=mid+1;
}
else{
r=mid-1;
}
}
}
if(ret){
if(ret!=i){
if(d==0&&t[a[ret]]-2>=1){//0的情况
t[a[ret]]-=2;
cnt++;
}
vis[ret]=1;
cnt++;
}
}
}
cout<<cnt;
return 0;
}
//1 2 2 2 3 4 5 5 10 10
//1 1 3 4 5
相关推荐
评论
共 9 条评论,欢迎与作者交流。
正在加载评论...