2020.06.26日常总结

UVA11039 Building Designing\color{green}{\texttt{UVA11039 Building Designing}}

[Problem]\color{blue}{\texttt{[Problem]}}

  • nn 个绝对值不相等的非 00 整数,选出尽可能多的数,使得它们可以排成一个正负号交替,绝对值递增的序列。给定 nn 和该序列,输出最长的符合条件序列的长度。
  • 序列中元素不一定要按照输入顺序排列。1n5×1051 \leq n \leq 5 \times 10^5

[Soluntion]\color{blue}{\texttt{[Soluntion]}}

贪心。

直接将原数据按绝对值从小到大排序,然后把第一个数给选了,再枚举,如果当前数的符号和上一个选的数的符号相反,就把它给选了。

下面是个人的证明,各位 dalao 不想看就不看了。

假设我们现在在考虑第 ii 个元素选或不选,有两种情况:

  • ii 不能选。

    因为我们已经将原序列按绝对值从小到大排序了,所以不存在说第 ii 个数因为绝对值小于前一个选择的数而不能选的情况。那么就只剩下一种情况了:那就是 ii 和前一个被现在的数的符号相同。

    既然两个数符号相同,那么必然是有我不能有你,有你不能有我,可以用 ii 替代前一个数,但是没必要,毕竟答案是不变的,没必要给自己增加麻烦。

    综上:当 ii 不能选时,不选。

  • ii 可以选。

    可能大家会有个这样的担心,会不会答案中 ii 是不选的,但是我们却误认为 ii 是可以选的呢?

    答案是否定的。为什么呢?第一,因为绝对值比 ii 小的数我们都已经考虑到了,现在我们就不考虑了。第二,如果 ii 不选,必然会有另一个数 jj 来代替 ii(否则 ii 就是最后一个数,直接选更优)。

    根据第一,j>i|j|>|i|,既然 iijj 也是有其一无其二,那么我们选一个绝对值小的元素给后面的选择可以留下更大的空间。

    综上:当 ii 可以选时,必须选。

[code]\color{blue}{\texttt{[code]}}

#define gc getchar()
#define g(c) isdigit(c)
inline int read(){
	char c=0;int x=0;bool f=0;
	while (!g(c)) f=c=='-',c=gc;
	while (g(c)) x=x*10+c-48,c=gc;
	return f?-x:x;
}
const int N=5e5+100;
int a[N],ans,n,test_number;
inline bool cmp(int x,int y){
	return abs(x)<abs(y);
}
inline bool check(int f,int l){
	if (a[f]/abs(a[f])==a[l]/abs(a[l]))
		return false;//符号不相反,不符合题意 
	else return true;//已经排序不用考虑绝对值 
}
int main(){
	test_number=read();//组数 
	while (test_number--){
		ans=1;n=read();//输入加上初始化 
		for(int i=1;i<=n;i++) a[i]=read();
		sort(a+1,a+n+1,cmp);//按绝对值排序 
		for(register int i=2,lst=1;i<=n;i++)
			if (check(i,lst)){ans++;lst=i;}
		printf("%d\n",ans);//输出答案 
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章