- 有 个绝对值不相等的非 整数,选出尽可能多的数,使得它们可以排成一个正负号交替,绝对值递增的序列。给定 和该序列,输出最长的符合条件序列的长度。
- 序列中元素不一定要按照输入顺序排列。。
贪心。
直接将原数据按绝对值从小到大排序,然后把第一个数给选了,再枚举,如果当前数的符号和上一个选的数的符号相反,就把它给选了。
下面是个人的证明,各位 dalao
不想看就不看了。
假设我们现在在考虑第 个元素选或不选,有两种情况:
-
不能选。
因为我们已经将原序列按绝对值从小到大排序了,所以不存在说第 个数因为绝对值小于前一个选择的数而不能选的情况。那么就只剩下一种情况了:那就是 和前一个被现在的数的符号相同。
既然两个数符号相同,那么必然是有我不能有你,有你不能有我,可以用 替代前一个数,但是没必要,毕竟答案是不变的,没必要给自己增加麻烦。
综上:当 不能选时,不选。
-
可以选。
可能大家会有个这样的担心,会不会答案中 是不选的,但是我们却误认为 是可以选的呢?
答案是否定的。为什么呢?第一,因为绝对值比 小的数我们都已经考虑到了,现在我们就不考虑了。第二,如果 不选,必然会有另一个数 来代替 (否则 就是最后一个数,直接选更优)。
根据第一,,既然 和 也是有其一无其二,那么我们选一个绝对值小的元素给后面的选择可以留下更大的空间。
综上:当 可以选时,必须选。
#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);//输出答案
}
}