题解:P10729 [NOISG 2023 Qualification] Dolls
看大家都是用并查集写的,我不是,所以来交一发题解。
题意转化
本题可以看作往桶里装数,两个数之间必须间隔至少 \(1\) 才能都被选中(即对 \(ans\) 带来贡献,否则相邻的只有一个能被选中。
分析
题目的特殊性质给了我很好的启发:
第一个特殊性质“\(a_i\) 为奇数”,实际上就是每个数都可以被选中,同样例 2。
第二个特殊性质“\(a_i\) 不为 \(4\) 的倍数”,在填地最满的情况下,形如这样:
11101110111
TFTFTFTFTFT
其中,1 代表有数,0 代表没数,第二行的 T 和 F 分别代表对答案有贡献与无贡献。
正解
我们再将以上的特殊性质推广,得到以下结论:
对于一个连续有数的区间,对答案的贡献为 \(\lfloor \frac{len}{2} \rfloor\) 。
在操作中,每次读入一个数的位置,遵循以下规则操作:
-
如果这个位置原先有数,直接输出 \(ans\) ,然后跳过。
-
如果这个数的前后有数,当且仅当所有与其相邻的区间长度为偶数,它才对答案有贡献,然后维护区间合并
代码
#include<bits/stdc++.h>
using namespace std;
int n;
pair<int,int> a[500010];
int ans;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
int x;cin>>x;
if(a[x]!=make_pair(0,0)){//这个点已经有数了
cout<<ans<<' ';
continue;
}
if(a[x-1]==make_pair(0,0)&&a[x+1]==make_pair(0,0)){//这个点周围没有数
a[x]=make_pair(x,x);
ans++;
}
else{
if(a[x-1]!=make_pair(0,0)&&a[x+1]!=make_pair(0,0)){//这个点前后都有数
if((a[x-1].second-a[x-1].first+1)%2==0&&(a[x+1].second-a[x+1].first+1)%2==0)ans++;
a[x]=make_pair(1,1);
a[a[x-1].first].second=a[x+1].second;
a[a[x+1].second].first=a[x-1].first;
}
else if(a[x-1]!=make_pair(0,0)){//这个点前面有数
a[x]=make_pair(a[x-1].first,x);
a[a[x-1].first].second=x;
ans+=(a[x].second-a[x].first+1)%2;
}
else{//这个点后面有数
a[x]=make_pair(x,a[x+1].second);
a[a[x+1].second].first=x;
ans+=(a[x].second-a[x].first+1)%2;
}
}
cout<<ans<<' ';
}
return 0;
}

浙公网安备 33010602011771号