#698 (Div. 2)C. Nezzar and Symmetric Array(数学)

题目描述

Long time ago there was a symmetric array a1,a2,…,a2n consisting of 2n distinct integers. Array a1,a2,…,a2n is called symmetric if for each integer 1≤i≤2n, there exists an integer 1≤j≤2n such that ai=−aj.
For each integer 1≤i≤2n, Nezzar wrote down an integer di equal to the sum of absolute differences from ai to all integers in a, i. e. di=∑2nj=1|ai−aj|.
Now a million years has passed and Nezzar can barely remember the array d and totally forget a. Nezzar wonders if there exists any symmetric array a consisting of 2n distinct integers that generates the array d.

Input

The first line contains a single integer t (1≤t≤105) — the number of test cases.
The first line of each test case contains a single integer n (1≤n≤105).
The second line of each test case contains 2n integers d1,d2,…,d2n (0≤di≤10^12).
It is guaranteed that the sum of n over all test cases does not exceed 105.

Output

For each test case, print “YES” in a single line if there exists a possible array a. Otherwise, print “NO”.
You can print letters in any case (upper or lower).

Example

input
6
2
8 12 8 12
2
7 7 9 11
2
7 11 7 11
1
1 1
4
40 56 48 40 80 56 80 48
6
240 154 210 162 174 154 186 240 174 186 162 210
output
YES
NO
NO
NO
NO
YES

Note

In the first test case, a=[1,−3,−1,3] is one possible symmetric array that generates the array d=[8,12,8,12].
In the second test case, it can be shown that there is no symmetric array consisting of distinct integers that can generate array d.

题目大意

有一个长度为2*n的序列a[i],a[]中的元素是对称的即如果序列中存在一个a[i],那么序列中就一定存在一个a[j]=-a[i])。通过a[]算出一个d[]序列。
d[i]= ∑ j = 1 2 ∗ n ∣ a i − a j ∣ \displaystyle\sum_{j=1}^{2*n} |a_i-a_j| j=12naiaj。 现在给出一个d[]序列,问是否该序列能还原出一个a[]序列。

题目分析

前提条件1。根据d[i]的计算公式可以发现:d[i]的值与a[]序列中的数值有关,而与a[]序列中数值的位置无关。因此在求解答案的过程中,我们是可以对d[]中数的位置进行改变的

前提条件2。在序列中如果 ∣ a [ i ] ∣ > ∣ a [ j ] ∣ |a[i]|>|a[j]| a[i]>a[j],那么一定有 d [ i ] > d [ j ] d[i]>d[j] d[i]>d[j] (这个条件我不太会证明,大家多找几个数试试就知道了)。

前提条件3。如果a[i]=-a[j],那么一定有d[i]=d[j]。d[i]=∑|a[i]-a[k]|,d[j]=∑|a[j]-a[k]|=∑|a[i]+a[k]|。因为a[]序列是对称的(本题对称的定义请看上面的题目大意)因此d[i]=d[j]。

因此我们可以对d[]进行升序排序。排完序后得d[]序列为d[1]=d[2]<d[3]=d[4]<……<a[2n-1]=d[2n]。
其对应的a[]序列为:a[1]=-a[2]<a[3]=-a[4]<……<a[2n-1]=-a[2n]。

此时我们假设a[]中奇数项为正数,偶数项为负数,得:
d[1] = |a[1]-a[1]| + |a[1]-a[2]| + |a[1]-a[3]| + |a[1]-a[4]| + …… +|a[1]-a[2n-1]| + |a[1]-a[2n]| = 2 ∗ * a[1] + |a[1]-a[3]| + |a[1]+a[3]| +……+ |a[1]-a[2n-1]| + |a[1]+a[2n-1]|;

d[3] = |a[3]-a[1]| + |a[3]-a[2]| + |a[3]-a[3]| + |a[3]-a[4]| + …… +|a[3]-a[2n-1]| + |a[3]-a[2n]| = 2 ∗ * a[3] + |a[3]-a[1]| + |a[3]+a[1]| +……+ |a[3]-a[2n-1]| + |a[3]+a[2n-1]|;

……

d[2n-1] = |a[2n-1]-a[1]| + |a[2n-1]-a[2]| + |a[2n-1]-a[3]| + |a[2n-1]-a[4]| + …… +|a[2n-1]-a[2n-1]| + |a[2n-1]-a[2n]| = 2 ∗ * a[2n-1] + |a[2n-1]-a[1]| + |a[2n-1]+a[1]| +……+ |a[2n-1]-a[2n-3]| + |a[2n-1]+a[2n-3]|;

因为a[]中所有数得大小关系均已确定,因为我们可以把绝对值符合取掉:
d[1]=2 ∗ * a[1] +(a[3]-a[1] + a[1]+a[3])+……+(a[2n-1]-a[1] + a[1]+a[2n-1])=2 ∗ * a[1]+2 ∗ * a[3]+……+2 ∗ * a[2n-1]

d[3]=2 ∗ * a[3] +(a[3]-a[1] + a[3]+a[1])+……+(a[2n-1]-a[3] + a[3]+a[2n-1])=4 ∗ * a[3]+2 ∗ * a[5]+……+2 ∗ * a[2n-1]

d[2n-1]=2 ∗ * a[2n-1] +(a[2n-1]-a[1] + a[2n-1]+a[1])+……+(a[2n-1]-a[2n-3] + a[2n-1]+a[2n-3])=2n ∗ * a[2n-1]

最后解得:d[2x-1]=2x*a[2x-1]+2*a[2x+1]+……+2*a[2n-1];
有了这个公式,我们就可以通过d[]序列求出a[]序列来了,在计算得过程中,判断求出得a[i]是否合法。如果算出来得序列最终整个是合法得,那么输出YES。

a[i]不能小于等于0,a[i]中的元素不能有重复(别问我怎么知道的。。。)

代码如下
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
#include <queue>
#include <vector>
#include <set>
#include <bitset>
#include <algorithm>
#define LL long long
#define PII pair<int,int>
#define x first
#define y second
using namespace std;
const int N=2e5+5;
LL d[N];				//d[]中的数会爆int,因此要用longlong来存
bool check(int n)		//判断长度为2n的d[]序列中是否只有n种数(前提条件3)
{
	for(int i=2;i<=n;i+=2)
		if(d[i-1]!=d[i]) return false;
	return true;
}
int main()
{
    int t;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d",&n);
		n<<=1;
		for(int i=1;i<=n;i++) scanf("%lld",&d[i]);
		sort(d+1,d+1+n,greater<LL>());			//因为a[i]只能是从大到小求,因此可以直接从大到小排序
		if(!check(n))
		{
			puts("NO");
			continue;
		}
		LL sum=0,a=0;
		bool flag=true;
		for(int i=2;i<=n;i+=2)
		{
			d[i]-=2*sum;				//使d[i]中只剩下(n-i+2)*a[i](代码中的d[]与分析中的d[]是相反的)
			if(d[i]%(n-i+2)||d[i]<=0||a==d[i]/(n-i+2))		//“注”中的条件,判断所求的a[i]是否合法
			{
				flag=false;
				break;
			}
			a=d[i]/(n-i+2);			//用a保存本次的结果
			sum+=a;
		}
		if(flag) puts("YES");
		else puts("NO");
	}
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lwz_159

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值