思路
对于任意的一个序列,它的答案只有两种可能,Yes
和 No
,这里分开讨论:
Yes
:此时,这个序列必定能分成若干个子序列使得这些子序列的极差相等,那么,它也必然能分成两个子序列使得这两个子序列极差相等。No
:此时,这个序列肯定无法分成两个子序列使得这两个子序列极差相等。
综上所述,可以发现,只要能分成两个极差相等的子序列的话,答案就为 Yes
,反之为 No
。
设序列 a a a 中的最大值为 max \max max,最小值为 min \min min,有以下两种情况:
- max \max max 与 min \min min 都在 a a a 中出现过多次:将一组 max \max max 与 min \min min 放在第一个序列里,再将另外一组 max \max max 与 min \min min 放在第二个序列里,再将其余的元素随意摆放,此时极差相等。
- max \max max 与 min \min min 在 a a a 中都只出现过 1 1 1 次:将 max \max max 放在第一个序列里, min \min min 放在第二个序列里,设第一个序列的最小值为 x x x,第二个序列的最大值为 y y y,可以得出等式: max − x = y − min \max-x=y-\min max−x=y−min,移项后得到: max + min = x + y \max+\min=x+y max+min=x+y。
可以发现,以上两种情况都可以用等式
max
+
min
=
x
+
y
\max+\min=x+y
max+min=x+y(第一种情况为
max
−
min
=
max
−
min
\max-\min=\max-\min
max−min=max−min,用
x
x
x 和
y
y
y 代替其中一个
max
\max
max 和一个
min
\min
min 后可以得到
max
+
min
=
x
+
y
\max+\min=x+y
max+min=x+y)来表示,再通过这个等式得到
max
+
min
−
x
=
y
\max+\min-x=y
max+min−x=y,所以,对于任意的一个
i
i
i,只要能找到一个
j
j
j ,使得
max
+
min
−
a
i
=
a
j
\max+\min-a_i=a_j
max+min−ai=aj,且
i
,
j
i,j
i,j 均不与
max
\max
max 和
min
\min
min 的下标相等的话,答案就为 Yes
。
显然,直接套两层 for
循环时间复杂度为
O
(
∑
n
2
)
\mathcal{O}(\sum n^2)
O(∑n2),会 TLE,实际上此题可以考虑使用二分法。首先对
a
a
a 进行升序排序,此时的
max
\max
max 就是
a
n
a_n
an,
min
\min
min 就是
a
1
a_1
a1。此时对于任意一个
i
i
i,使用二分法判断
a
a
a 中是否出现了值为
max
+
min
−
a
i
\max+\min-a_i
max+min−ai 的元素,如果出现了,且它所在的下标不为
1
1
1、
n
n
n 和
i
i
i 中的任意一个时,答案就为 Yes
。需要注意的是,如果这个下标等于了
i
i
i,还要额外判断
a
i
−
1
a_{i-1}
ai−1 和
a
i
+
1
a_{i+1}
ai+1 是否等于
max
+
min
−
a
i
\max+\min-a_i
max+min−ai,不过要保证
i
−
1
i-1
i−1 和
i
+
1
i+1
i+1 不与
1
1
1 或
n
n
n 相等。
Code
时间复杂度 O ( ∑ n log n ) \mathcal{O}(\sum n\log n) O(∑nlogn)。
#include<iostream>
#include<algorithm>
using namespace std;
int t,id,n,arr[1000000];//个人习惯用arr
bool judment(int l,int m,int r,int i,int sum) {//二分法判断这个值是否存在
if(l>r) return false;
if(arr[m]>sum) return judment(l,(l+m)/2,m-1,i,sum);
else if(arr[m]<sum) return judment(m+1,(m+r+2)/2,r,i,sum);
else if(m!=i) return true;//下标不能相等
else if((m>1&&arr[m-1]==sum)||(m<n-2&&arr[m+1]==sum)) return true;//额外的判断
return false;
}
signed main() {
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
bool flag;
cin>>t>>id;
while(t--) {
cin>>n;
for(int i=0;i<n;++i) cin>>arr[i];
sort(arr,arr+n);
flag=false;//判断答案是Yes还是No,Yes为true,No为false,初始要赋为false
for(int i=1;i<n-1;++i)
if(judment(1,(n-1)/2,n-2,i,arr[0]+arr[n-1]-arr[i])) {//判断arr中是否存在该元素
flag=true;//如果答案为Yes则将其该为true
break;
}
if(flag) cout<<"Yes\n";
else cout<<"No\n";
}
return 0;
}