传送门
一、题意: 现在有一个长度为2n的数组d,它可能是由一个长度为2n的数组a转变而来的,而数组a是一个对称数组(不存在重复的数字,并且对于每个a[i],总能找到一个a[j]==-a[i]),而d[i]是该位置的a[i]与其他所有2n-1个位置的元素的差的绝对值之和。
问是否存在这样一个数组a,若存在输出YES,否则NO
二、思路: 经过多组样例测试我们可以发现一个规律:
当|a[i]|>|a[j]|时,a[i]与a[j]和与-a[j]的差的绝对值之和会等于2a[i]。
假设|a[i]|为a数组中的最大值,因为不存在相同的元素,所以a[i]与其他任何一个a[j]和-a[j]的差的绝对值都会等于2a[i],再加上与-a[i]的差的绝对值,在d[i]的位置将会等于(2*a[i])*n,那么我们就可以通过d[i]来获得a[i]。
三、方法: 我们可以将d数组按降序排序,假设遍历到d[i]位置,我们可以假设将1-i-1位置的元素都已经删除,那么d[i]位置将会是数组的最大值的位置,那么就可以按照上述方法来求出a[i]的值。
因为d[i]也包括了与比a[i]大的值的差的绝对值,所以在遍历过程中要记录下前2a[1]+…2a[i-1]的值,用d[i]减去即可。
求出的a[i]如果不是0,不是重复,不是负数,则符合条件,否则直接跳出。
cpp代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<queue>
#include<vector>
#include<stack>
#define int long long
using namespace std;
int d[200004];
map<int, int>ma,vis;
int cmp(int x, int y) {
return x > y;
}
signed main()
{
int t;
scanf("%lld", &t);
while (t--) {
ma.clear();
vis.clear();
int n;
scanf("%lld", &n);
int flag = 1, ans = 0;
for (int i = 1; i <= 2 * n; i++) {
scanf("%lld", &d[i]);
ma[d[i]]++;
if (ma[d[i]] == 1)ans++;
else if (ma[d[i]] == 2)ans--;
if (d[i] % 2 != 0) {
flag = 0;
}
}
if (!flag) {
printf("NO\n");
continue;
}
if (ans) {
printf("NO\n");
continue;
}
sort(a + 1, a + 1 + 2 * n, cmp);
ans = 0;
for (int i = 1; i <= 2 * n; i += 2) {
if ((d[i] - ans) % ((n - (i - 1) / 2) * 2) == 0 && d[i] - ans > 0) {
int p = (d[i] - ans) / ((n - (i - 1) / 2) * 2);
if (!vis[p]) {
ans += ((d[i] - ans) / ((n - (i - 1) / 2) * 2)) * 2;
vis[p] = 1;
}
else {
flag = 0;
break;
}
}
else {
flag = 0;
break;
}
}
if (flag)printf("YES\n");
else
printf("NO\n");
}
return 0;
}