赞
踩
传送门
Time Limit: 2 seconds
Memory Limit: 512 megabytes
Long time ago there was a symmetric array a 1 , a 2 , … , a 2 n a_1,a_2,\ldots,a_{2n} a1,a2,…,a2n consisting of 2 n 2n 2n distinct integers. Array a 1 , a 2 , … , a 2 n a_1,a_2,\ldots,a_{2n} a1,a2,…,a2n is called symmetric if for each integer 1 ≤ i ≤ 2 n 1 \le i \le 2n 1≤i≤2n, there exists an integer 1 ≤ j ≤ 2 n 1 \le j \le 2n 1≤j≤2n such that a i = − a j a_i = -a_j ai=−aj.
For each integer 1 ≤ i ≤ 2 n 1 \le i \le 2n 1≤i≤2n, Nezzar wrote down an integer d i d_i di equal to the sum of absolute differences from a i a_i ai to all integers in a a a, i. e. d i = ∑ j = 1 2 n ∣ a i − a j ∣ d_i = \sum_{j = 1}^{2n} {|a_i - a_j|} di=∑j=12n∣ai−aj∣.
Now a million years has passed and Nezzar can barely remember the array d d d and totally forget a a a. Nezzar wonders if there exists any symmetric array a a a consisting of 2 n 2n 2n distinct integers that generates the array d d d.
The first line contains a single integer t t t ( 1 ≤ t ≤ 1 0 5 1 \le t \le 10^5 1≤t≤105) — the number of test cases.
The first line of each test case contains a single integer n n n ( 1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1≤n≤105).
The second line of each test case contains 2 n 2n 2n integers d 1 , d 2 , … , d 2 n d_1, d_2, \ldots, d_{2n} d1,d2,…,d2n ( 0 ≤ d i ≤ 1 0 12 0 \le d_i \le 10^{12} 0≤di≤1012).
It is guaranteed that the sum of n n n over all test cases does not exceed 1 0 5 10^5 105.
For each test case, print “YES” in a single line if there exists a possible array a a a. Otherwise, print “NO”.
You can print letters in any case (upper or lower).
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
YES
NO
NO
NO
NO
YES
In the first test case, a = [ 1 , − 3 , − 1 , 3 ] a=[1,-3,-1,3] a=[1,−3,−1,3] is one possible symmetric array that generates the array d = [ 8 , 12 , 8 , 12 ] d=[8,12,8,12] 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 d d.
原来有2n个数,各不相同,这2n个数中,每个数的相反数也在其中。
Nezzar在100万年前计算出了 每个数与其他数的差值 的和,但忘掉了原来那2n个数。
问从这2n个计算出来的差值和能不能推出一个满足条件的2*n个数。
举个例子,假如原来这6个数是 ±2、±7、±9
那么
原数 | 差值和 |
---|---|
-2 | 36 |
2 | 36 |
-7 | 46 |
7 | 46 |
-9 | 54 |
9 | 54 |
-2的差值和就是abs(2-(-2)) + abs(-7-(-2)) + abs(7-(-2)) + abs(-9-(-2)) + abs(9-(-2))
先研究2:
2与-2的差值是两个2(2的两倍)
2与±7的差值和是两个7(7的两倍)
2与±9的差值和是两个9(9的两倍)
再研究7:
7与±2的差值和是两个7(7的两倍)
7与-7的差值是两个7(7的两倍)
7与±9的差值和是两个9(9的两倍)
最后研究9:
9与±2的差值和是两个9(9的两倍)
9与±7的差值和是两个9(9的两倍)
9与-9的差值是两个9(9的两倍)
所以有
差值和 | 来历 |
---|---|
36 | 2*(2+7+9) |
46 | 2*(7+7+9) |
54 | 2*(9+9+9) |
在计算过程中,每一个计算出的原来的数需要满足一下条件:
但是这样交上去还是没有考虑完所有的情况,还有一点就是计算出的原来的数的范围:>1
这是因为前面我们是只考虑整数才得出的结论,所以如果计算过程中出现了负数(或0),就不可以继续还原。
条件一:差值和们 成对出现
条件二:差值和都为偶数
条件三:原来的数是整数(可以整除)
条件四:原来的数各不相同
条件五:计算过程中的数都是正数
其中,条件三和条件五可以合并为
计算过程中的数都是正整数
总之,只需要满足
条件一:差值和们 成对出现
条件二:差值和都为偶数
条件三:计算过程中的数都是正整数
#include <bits/stdc++.h> using namespace std; typedef long long ll; ll really[100010]; // Really 记录真正需要处理的数(表格二左边的1/2) int main() { int N; cin >> N; while (N--) { int n; scanf("%d", &n); bool buxing = 0; //不行的拼音 map<ll, int> ma; //用map记录出现了几次(条件一) for (int i = 0; i < 2 * n; i++) { ll t; scanf("%lld", &t); if (t % 2) //差值和是否为偶数(条件二) buxing = 1; ma[t]++; } int sum = 1; ll realOriSum = 0; // 已经得出的原来的数,上文样例中便是 9 7 3 if (buxing) { puts("NO"); } else { for (map<ll, int>::iterator it = ma.begin(); it != ma.end(); it++) { if (it->second != 2) // 差值和是否都出现了两处(条件一) buxing = 1; really[sum++] = (it->first) / 2; } if (buxing) { puts("NO"); } else { for (sum--; sum > 0; sum--) { ll all = really[sum] - realOriSum; //减去原来的数 if (all % sum) //是否可以整除 buxing = 1; ll thisReal = all / sum; realOriSum += thisReal; if (thisReal <= 0) buxing = 1; } if (buxing) { puts("NO"); } else puts("YES"); } } } return 0; }
2021-1-29更
上文中的例子原始数组±2、±7、±9
那么题目要给的差值和为 36 36 46 54 46 54(顺序不一定)
去重排序除以2(用really数组保存)18 23 27
27/3=9,所以原始数组中最大的数就是9
(23-9)/2=7,所以原始数组中还有一个正数7
(18-9-7)/1=2,所以原始数组中还有一个正数2
所以原始数组为±2、±7、±9,输出YES
/*CSDN简化版本*/ #include <bits/stdc++.h> using namespace std; typedef long long ll; // 用ll来代替long long /*really[] 题目给的是计算出的差值和,是无序且重复的 这个really数组就是用来有序地记录这些差值和的一半的 比如上文所举的例子,±2、±7、±9 那么题目所给的差值和就是 36 36 46 46 54 54 而really数组中要记录的就是 18 23 27 (差值和的一半) 除以二是因为表格二,差值和都是原数和的两倍 */ ll really[100010]; int main() { int N; cin >> N; //共有N个test cases while (N--) { int n; scanf("%d", &n); bool buxing = false; //“不行”的拼音,一旦为true就说明这组样例“不行” map<ll, int> ma; //用map记录出现了几次(条件一) for (int i = 0; i < 2 * n; i++) { ll t; scanf("%lld", &t); if (t % 2) //差值和是否为偶数(条件二) buxing = 1; //如果t%2有余数,则说明这个数是奇数 ma[t]++; //t出现的次数加一 } int sum = 1; //really数组中需要放置的数的下标,笔者选择从下标1开始存放 ll realOriSum = 0; // 这是计算出来的原数组中的数,上文样例中便是 9 7 3 /*ma的迭代器,这个for循环从小到大遍历了插入ma中的差值和*/ for (map<ll, int>::iterator it = ma.begin(); it != ma.end(); it++) { /*it->second就是这个差值和出现的次数*/ if (it->second != 2) // 差值和是否都出现了两处(条件一) buxing = 1; /*it->first是这个差值和*/ really[sum++] = (it->first) / 2; // 差值和的一半存放到really数组中 } for (sum--; sum > 0; sum--) { ll all = really[sum] - realOriSum; //减去原来的数 if (all % sum) //是否可以整除 buxing = 1; ll thisReal = all / sum; // 这个是原始数组(计算差值和之前那个±2±7±9的数组) realOriSum += thisReal; // 求出的原始的数的和 if (thisReal <= 0) // 按上述方法,原来的数必须是正数 buxing = 1; } if (buxing) //如果不行buxing就会为true,这个样例从头到尾都可以,buxing就还是原来初始的false puts("NO"); else //否则就可以 puts("YES"); } return 0; }
打竞赛需要能够静下心来思考。
重在思路,次在代码具体实现。
代码能不能看懂不重要,思路想明白了才是最重要的。
如有错误,欢迎指正,您的批评将是我前进的动力。
加油加油~
写到凌晨两点不容易,喜欢了就点个赞再走叭
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。