2020.06.26日常总结

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

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

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

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

贪心。

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

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

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

  • i i i 不能选。

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

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

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

  • i i i 可以选。

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

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

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

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

[code] \color{blue}{\texttt{[code]}} [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);//输出答案 
	}
}

你可能感兴趣的:(贪心)