a数组有2n个元素,两两不同,且每个数和它的绝对值同时出现。如[-3,3,-1,1]。
根据公式 d i = ∑ j = 1 2 n ∣ a i − a j ∣ d_{i}=\sum_{j=1}^{2 n}\left|a_{i}-a_{j}\right| di=∑j=12n∣ai−aj∣ 求得d数组。即:d数组中每个元素,为a数组相应元素和其他所有元素绝对值的和。
已知d数组,求是否存在合法的a数组。
显然,d数组和a数组中,元素的顺序没什么卵用
假设a数组从大到小排好了序,只考虑a数组中的正数(也就是前n个)
容易发现
d i = ∑ j = 1 n m a x ( 2 a i , 2 a j ) d_i= \sum_{j=1}^{n} max(2a_i,2a_j) di=∑j=1nmax(2ai,2aj)
看图!
例如a=[6,3,1,-1,-3,-6]
d 1 = 2 ∗ 6 + 2 ∗ 6 + 2 ∗ 6 = 36 d_1=2*6+2*6+2*6=36 d1=2∗6+2∗6+2∗6=36,因为 m a x ( 6 , 6 ) = 6 , m a x ( 6 , 3 ) = 6 , m a x ( 6 , 1 ) = 6 max(6,6)=6, max(6,3)=6, max(6,1)=6 max(6,6)=6,max(6,3)=6,max(6,1)=6
d 2 = 2 ∗ 6 + 2 ∗ 3 + 2 ∗ 3 = 24 d_2=2*6+2*3+2*3=24 d2=2∗6+2∗3+2∗3=24,因为 m a x ( 3 , 6 ) = 6 , m a x ( 3 , 3 ) = 3 , m a x ( 3 , 1 ) = 3 max(3,6)=6, max(3,3)=3, max(3,1)=3 max(3,6)=6,max(3,3)=3,max(3,1)=3
d 3 = 2 ∗ 6 + 2 ∗ 3 + 2 ∗ 1 = 20 d_3=2*6+2*3+2*1=20 d3=2∗6+2∗3+2∗1=20,因为 m a x ( 1 , 6 ) = 6 , m a x ( 1 , 3 ) = 3 , m a x ( 1 , 1 ) = 1 max(1,6)=6, max(1,3)=3, max(1,1)=1 max(1,6)=6,max(1,3)=3,max(1,1)=1
所以d=[36,24,20,20,24,36]
由于顺序没卵用,因此,若d数组是这一坨数,不管顺序如何,都一定YES
假设a数组从大到小排列,假设a数组从大到小排列,假设a数组从大到小排列,重要的事情说三遍!后文默认a是从大到小排好序的。d数组根据公式推出:
首先, d 1 = 2 n a 1 d_1=2na_1 d1=2na1,因为 a 1 a_1 a1一定是a数组中最大的数,根据上述公式, d 1 = 2 a 1 + 2 a 1 + ⋯ + 2 a 1 = 2 n a 1 d_1=2a_1+2a_1+\cdots+2a_1=2na_1 d1=2a1+2a1+⋯+2a1=2na1。
只有 a 1 > a 2 a_1>a_2 a1>a2,而且 a 3 ⋯ a n a_3\cdots a_n a3⋯an均小于 a 2 a_2 a2。因此 d 2 = 2 a 1 + 2 a 2 + 2 a 2 + ⋯ + 2 a 2 = 2 a 1 + 2 ( n − 1 ) a 2 d_2=2a_1+2a_2+2a_2+\cdots+2a_2=2a_1+2(n-1)a_2 d2=2a1+2a2+2a2+⋯+2a2=2a1+2(n−1)a2
同理可得 d 3 = 2 a 1 + 2 a 2 + 2 ( n − 2 ) a 3 d_3=2a_1+2a_2+2(n-2)a_3 d3=2a1+2a2+2(n−2)a3
d k = 2 a 1 + 2 a 2 + ⋯ + 2 a k − 1 + 2 ( n − k + 1 ) a k d_k=2a_1+2a_2+ \cdots+2a_{k-1}+2(n-k+1)a_k dk=2a1+2a2+⋯+2ak−1+2(n−k+1)ak
对于a的负数部分,其对应的d和正数部分对称出现。即 a 1 = − a 2 n , d 1 = d 2 n ; a 2 = − a 2 n − 1 , d 2 = d 2 n − 1 a_1=-a_{2n}, d_1=d_{2n}; a_2=-a_{2n-1}, d_2=d_{2n-1} a1=−a2n,d1=d2n;a2=−a2n−1,d2=d2n−1。也就是说,d数组中的数必须成对出现。由于上面的公式每一项都乘了2,因此d数组中的数必须都是偶数。
这一顿操作猛如虎,有什么用呢?别急!马上出来了!
首先,都是偶数,可以在输入时就进行判断。
其次,必须成对出现,从大到小排序后,必须满足“对于任意的奇数i( 1 ≤ i ≤ 2 n − 1 1\leq i\leq 2n-1 1≤i≤2n−1),有 d [ i ] = = d [ i + 1 ] d[i]==d[i+1] d[i]==d[i+1]。判断的过程可以同时去重,以便和上述的a数组对应,如d1对应a1。
然后!!!!!
假设d数组已经从大到小排列并去重(相同的两个数只保留一个)
由于 d 1 = 2 n a 1 d_1=2na_1 d1=2na1,所以必须有 d 1 % 2 ( n − 1 ) = = 0 d_1\%2(n-1)==0 d1%2(n−1)==0, a 1 = d 1 / 2 n a_1=d_1/2n a1=d1/2n
由于 d 2 = 2 a 1 + 2 ( n − 1 ) a 2 d_2=2a_1+2(n-1)a_2 d2=2a1+2(n−1)a2,所以必须有 ( d 2 − 2 a 1 ) % 2 ( n − 1 ) = = 0 (d_2-2a_1)\%2(n-1)==0 (d2−2a1)%2(n−1)==0, a 2 = ( d 2 − 2 a 1 ) / 2 ( n − 1 ) a_2=(d_2-2a_1)/2(n-1) a2=(d2−2a1)/2(n−1)
由于 d 3 = 2 a 1 + 2 a 2 + 2 ( n − 2 ) a 3 d_3=2a_1+2a_2+2(n-2)a_3 d3=2a1+2a2+2(n−2)a3,所以必须有 ( d 3 − 2 a 1 − 2 a 2 ) % 2 ( n − 2 ) = = 0 (d_3-2a_1-2a_2)\%2(n-2)==0 (d3−2a1−2a2)%2(n−2)==0
对于任意的 2 ≤ k ≤ n 2\leq k\leq n 2≤k≤n,有 ( d k − 2 a 1 − 2 a 2 − ⋯ − 2 a k − 1 ) % 2 ( n − k + 1 ) = = 0 (d_k-2a_1-2a_2-\cdots-2a_{k-1})\%2(n-k+1)==0 (dk−2a1−2a2−⋯−2ak−1)%2(n−k+1)==0
每次“减去的数”多了一个 2 a i 2a_i 2ai,因此可以用一个变量维护。如果其中任何一个不为0,则输出NO
还有!!!!!
我们假设a数组是单调递减且不重复的,前n个数是正数!!!!如果算到哪一步, d k − 2 a 1 − 2 a 2 − ⋯ 2 a k − 1 ≤ 0 d_k-2a_1-2a_2-\cdots2a_{k-1}\leq0 dk−2a1−2a2−⋯2ak−1≤0了,那就没了!!!!如果算出哪一步的 a i a_i ai大于上一步的 a i − 1 a_{i-1} ai−1,也不可以!!!!!
#include
#include
using namespace std;
#define ll long long
ll d[200005], n;
int main()
{
ios::sync_with_stdio(false);
int t; cin>>t;
while(t--)
{
cin>>n;
for(ll i=1;i<=n*2;i++)
cin>>d[i];
sort(d+1,d+2*n+1,[](ll x,ll y)->bool{
return x>y;}); //从大到小排序
bool flag = true;
for(ll i=1;i<=n*2-1;i+=2) //我没有去重!!!只判断了
{
if(d[i]%2 || d[i]!=d[i+1]) flag = false; //必须两两一组出现,而且得是偶数
}
if(d[1]%(n*2)!=0) flag = false;
ll pre = d[1]/n, cnt = 2*n, last = d[1]/n; //已经加的,剩余个数,上一个a[i]的二倍
for(ll i=3;i<=2*n-1 && flag;i+=2)
{
cnt-=2; //剩余数字个数-2
d[i] -= pre;
//cout<
flag &= (d[i]>0);
flag &= (d[i]%cnt==0);
pre += d[i]/cnt*2; //已经求过的数之和
ll now = d[i]/cnt*2; //这一个a[i]的二倍
flag &= (now<last); //a数组必须严格单调递减
//cout<
last = now;
}
if(flag) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}