CF1641A 题解

可能更好的阅读体验
题目传送门

题目大意

给定一个长度为 \(n\) 的序列 \(a\) 和一个数字 \(x\)
你需要在序列 \(a\) 后面加上一些元素,然后对整个序列重新排序,使得对于 \([1,n]\) 内的任意奇数 \(i\) 都有 \(a_i\cdot x=a_{i+1}\)
数据范围:\(n\le 2\times10^5,\sum n\le 2\times 10^5,2\le x\le10^6,1\le a_i\le 10^9\)

题目解析

考虑贪心。
首先把整个序列按升序排序。
然后从头到尾扫一次,如果 \(a_i\cdot x\) 存在,那么就把它删掉,否则就在序列里加入这个数字(也就是答案加一)。
我们发现需要使用哈希或者是平衡树来维护,这样就可以做到 \(O\left(n\right)\) 或者是 \(O\left(n\log n\right)\)

这里用 set 来维护。


我们发现 \(x\le 10^6,a_i\le 10^9\),也就是说 \(a_i\cdot x\le 10^{15}\),会爆 int,所以一定要开 long long听说 Div 2 一堆人因为没开 FST 了。

核心代码:

struct JTZ{
	ll x; int num;
	bool operator < (const JTZ x) const {
		if(this->x==x.x) return this->num < x.num;
		return this->x < x.x;
	}
};
set<JTZ> s,E;
int n,flag[maxn];
ll x,a[maxn];
void work(){
	s=E; n=read(); x=read(); int i,ans=0;
	for(i=1;i<=n;i++) a[i]=read(); sort(a+1,a+n+1);
	for(i=1;i<=n;i++) s.insert((JTZ){a[i],i}),flag[i]=1;
	for(i=1;i<=n;i++) if(flag[i]){
		flag[i]=0;
		s.erase((JTZ){a[i],i});
		set<JTZ>::iterator tmp=s.lower_bound((JTZ){a[i]*x,i});
		if((*tmp).x==a[i]*x) flag[(*tmp).num]=0,s.erase(tmp);
		else ans++;
	} print(ans),pc('\n'); return;
}
posted @ 2022-02-24 16:25  jiangtaizhe001  阅读(39)  评论(0编辑  收藏  举报