题意:
有(2n)个两两不同的数,每个数一定有另外一个数为它的相反数,定义(d_i)为第(i)个数到别的数的距离和。
现在已知(d_i),询问是否存在合法的数列可以生成(d)数列。
题解:
可以在数轴上画出这些数。
显然(d)数列必须是对称,且从原点向右单调递增。
于是可以排序判断每个数是否恰好出现两次。
去重后就是单调递增数列。
然后我们可以列出(a_i)的方程。
首先
[2*a_1+2*(a_2+dots+a_n) = d_1
]
[2*(a_1+a_2+dots+a_n) + 2*(a_2-a_1) = 4 * a_2 + 2*(a_3+dots+a_n) = d_2
]
[4 * a_2 + 2*(a_3+dots+a_n) + 4*(a_3-a_2) = 6 * a_3 + 2*(a_4+dots+a_n) = d_2
]
[dots
]
[2*n*a_n=d_n
]
倒着进行一遍高斯消元就行了。
由于后面系数相同,直接计算后缀和就可以直接消元了。
判断数列是否单调递减并且大于(0)即可(不能等于(0)因为(0==-0))
#include <bits/stdc++.h>
#define int long long
#define Mid ((l + r) >> 1)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
using namespace std;
int read(){
char c; int num, f = 1;
while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
return f * num;
}
const int N = 3e5 + 1009;
int n, a[N], minn;
void work() {
n = read(); minn = 1ll << 61;
for(int i = 1; i <= 2 * n; i++) a[i] = read();
sort(a + 1, a + 1 + 2 * n);
for(int i = 1; i <= n; i++) {
if(a[i * 2] != a[i * 2 - 1] || (i >= 2 && a[i * 2] == a[i * 2 - 2])) {
printf("NO
");
return ;
}
}
for(int i = 1; i <= 2 * n; i += 2)
a[i / 2 + 1] = a[i];
int del = 0;
for(int i = n; i; i--) {
a[i] -= del;
if(a[i] <= 0 || a[i] % (i * 2) != 0) {
printf("NO
");
return ;
}
del += 2 * (a[i] / (i * 2));
if(a[i] / (i * 2) >= minn) {
printf("NO
");
return ;
}
minn = a[i] / (i * 2);
}
printf("YES
");
}
signed main()
{
int Case = read();
while(Case--) work();
return 0;
}