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

C. Nezzar and Symmetric Array

題目大意

原來有2n個數,各不相同,這2n個數中,每個數的相反數也在其中。
Nezzar在100萬年前計算出了 每個數與其他數的差值 的和,但忘掉了原來那2n個數。
問從這2
n個計算出來的差值和能不能推出一個滿足條件的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),就不可以繼續還原。

這就需要 條件五 計算過程中的數都是正數

總結

條件一:差值和們 成對出現
條件二:差值和都爲偶數
條件三:原來的數是整數(可以整除)
條件四:原來的數各不相同
條件五:計算過程中的數都是正數



其中,條件三和條件五可以合併爲

計算過程中的數都是正整數

總之,只需要滿足

條件一:差值和們 成對出現
條件二:差值和都爲偶數
條件三:計算過程中的數都是正整數


AC代碼

#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;
}

結語

打競賽需要能夠靜下心來思考。
重在思路,次在代碼具體實現。
代碼能不能看懂不重要,思路想明白了纔是最重要的。
如有錯誤,歡迎指正,您的批評將是我前進的動力。
加油加油~



寫到凌晨兩點不容易,喜歡了就點個贊再走叭

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章