Loading

题解: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;
}
posted @ 2024-10-16 20:32  UserJCY  阅读(41)  评论(0)    收藏  举报
Title