Codeforces Round #698 (Div. 2)C Nezzar and Symmetric Array

传送门
一、题意: 现在有一个长度为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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值