只過了Pretest,可能有誤,歡迎批評指正
題面:https://codeforces.com/contest/1478/problem/C#
題意:
a數組有2n個元素,兩兩不同,且每個數和它的絕對值同時出現。如[-3,3,-1,1]。
根據公式 d i = ∑ j = 1 2 n ∣ a i − a j ∣ d_{i}=\sum_{j=1}^{2 n}\left|a_{i}-a_{j}\right| di=∑j=12n∣ai−aj∣ 求得d數組。即:d數組中每個元素,爲a數組相應元素和其他所有元素絕對值的和。
已知d數組,求是否存在合法的a數組。
思路:
顯然,d數組和a數組中,元素的順序沒什麼卵用
假設a數組從大到小排好了序,只考慮a數組中的正數(也就是前n個)
容易發現
d i = ∑ j = 1 n m a x ( 2 a i , 2 a j ) d_i= \sum_{j=1}^{n} max(2a_i,2a_j) di=∑j=1nmax(2ai,2aj)
看圖!
舉個例子
例如a=[6,3,1,-1,-3,-6]
d 1 = 2 ∗ 6 + 2 ∗ 6 + 2 ∗ 6 = 36 d_1=2*6+2*6+2*6=36 d1=2∗6+2∗6+2∗6=36,因爲 m a x ( 6 , 6 ) = 6 , m a x ( 6 , 3 ) = 6 , m a x ( 6 , 1 ) = 6 max(6,6)=6, max(6,3)=6, max(6,1)=6 max(6,6)=6,max(6,3)=6,max(6,1)=6
d 2 = 2 ∗ 6 + 2 ∗ 3 + 2 ∗ 3 = 24 d_2=2*6+2*3+2*3=24 d2=2∗6+2∗3+2∗3=24,因爲 m a x ( 3 , 6 ) = 6 , m a x ( 3 , 3 ) = 3 , m a x ( 3 , 1 ) = 3 max(3,6)=6, max(3,3)=3, max(3,1)=3 max(3,6)=6,max(3,3)=3,max(3,1)=3
d 3 = 2 ∗ 6 + 2 ∗ 3 + 2 ∗ 1 = 20 d_3=2*6+2*3+2*1=20 d3=2∗6+2∗3+2∗1=20,因爲 m a x ( 1 , 6 ) = 6 , m a x ( 1 , 3 ) = 3 , m a x ( 1 , 1 ) = 1 max(1,6)=6, max(1,3)=3, max(1,1)=1 max(1,6)=6,max(1,3)=3,max(1,1)=1
所以d=[36,24,20,20,24,36]
由於順序沒卵用,因此,若d數組是這一坨數,不管順序如何,都一定YES
d有什麼性質呢?
假設a數組從大到小排列,假設a數組從大到小排列,假設a數組從大到小排列,重要的事情說三遍!後文默認a是從大到小排好序的。d數組根據公式推出:
首先, d 1 = 2 n a 1 d_1=2na_1 d1=2na1,因爲 a 1 a_1 a1一定是a數組中最大的數,根據上述公式, d 1 = 2 a 1 + 2 a 1 + ⋯ + 2 a 1 = 2 n a 1 d_1=2a_1+2a_1+\cdots+2a_1=2na_1 d1=2a1+2a1+⋯+2a1=2na1。
只有 a 1 > a 2 a_1>a_2 a1>a2,而且 a 3 ⋯ a n a_3\cdots a_n a3⋯an均小於 a 2 a_2 a2。因此 d 2 = 2 a 1 + 2 a 2 + 2 a 2 + ⋯ + 2 a 2 = 2 a 1 + 2 ( n − 1 ) a 2 d_2=2a_1+2a_2+2a_2+\cdots+2a_2=2a_1+2(n-1)a_2 d2=2a1+2a2+2a2+⋯+2a2=2a1+2(n−1)a2
同理可得 d 3 = 2 a 1 + 2 a 2 + 2 ( n − 2 ) a 3 d_3=2a_1+2a_2+2(n-2)a_3 d3=2a1+2a2+2(n−2)a3
d k = 2 a 1 + 2 a 2 + ⋯ + 2 a k − 1 + 2 ( n − k + 1 ) a k d_k=2a_1+2a_2+ \cdots+2a_{k-1}+2(n-k+1)a_k dk=2a1+2a2+⋯+2ak−1+2(n−k+1)ak
對於a的負數部分,其對應的d和正數部分對稱出現。即 a 1 = − a 2 n , d 1 = d 2 n ; a 2 = − a 2 n − 1 , d 2 = d 2 n − 1 a_1=-a_{2n}, d_1=d_{2n}; a_2=-a_{2n-1}, d_2=d_{2n-1} a1=−a2n,d1=d2n;a2=−a2n−1,d2=d2n−1。也就是說,d數組中的數必須成對出現。由於上面的公式每一項都乘了2,因此d數組中的數必須都是偶數。
這一頓操作猛如虎,有什麼用呢?別急!馬上出來了!
那麼怎麼樣的一坨數纔算YES呢?
首先,都是偶數,可以在輸入時就進行判斷。
其次,必須成對出現,從大到小排序後,必須滿足“對於任意的奇數i( 1 ≤ i ≤ 2 n − 1 1\leq i\leq 2n-1 1≤i≤2n−1),有 d [ i ] = = d [ i + 1 ] d[i]==d[i+1] d[i]==d[i+1]。判斷的過程可以同時去重,以便和上述的a數組對應,如d1對應a1。
然後!!!!!
假設d數組已經從大到小排列並去重(相同的兩個數只保留一個)
由於 d 1 = 2 n a 1 d_1=2na_1 d1=2na1,所以必須有 d 1 % 2 ( n − 1 ) = = 0 d_1\%2(n-1)==0 d1%2(n−1)==0, a 1 = d 1 / 2 n a_1=d_1/2n a1=d1/2n
由於 d 2 = 2 a 1 + 2 ( n − 1 ) a 2 d_2=2a_1+2(n-1)a_2 d2=2a1+2(n−1)a2,所以必須有 ( d 2 − 2 a 1 ) % 2 ( n − 1 ) = = 0 (d_2-2a_1)\%2(n-1)==0 (d2−2a1)%2(n−1)==0, a 2 = ( d 2 − 2 a 1 ) / 2 ( n − 1 ) a_2=(d_2-2a_1)/2(n-1) a2=(d2−2a1)/2(n−1)
由於 d 3 = 2 a 1 + 2 a 2 + 2 ( n − 2 ) a 3 d_3=2a_1+2a_2+2(n-2)a_3 d3=2a1+2a2+2(n−2)a3,所以必須有 ( d 3 − 2 a 1 − 2 a 2 ) % 2 ( n − 2 ) = = 0 (d_3-2a_1-2a_2)\%2(n-2)==0 (d3−2a1−2a2)%2(n−2)==0
對於任意的 2 ≤ k ≤ n 2\leq k\leq n 2≤k≤n,有 ( d k − 2 a 1 − 2 a 2 − ⋯ − 2 a k − 1 ) % 2 ( n − k + 1 ) = = 0 (d_k-2a_1-2a_2-\cdots-2a_{k-1})\%2(n-k+1)==0 (dk−2a1−2a2−⋯−2ak−1)%2(n−k+1)==0
每次“減去的數”多了一個 2 a i 2a_i 2ai,因此可以用一個變量維護。如果其中任何一個不爲0,則輸出NO
還有!!!!!
我們假設a數組是單調遞減且不重複的,前n個數是正數!!!!如果算到哪一步, d k − 2 a 1 − 2 a 2 − ⋯ 2 a k − 1 ≤ 0 d_k-2a_1-2a_2-\cdots2a_{k-1}\leq0 dk−2a1−2a2−⋯2ak−1≤0了,那就沒了!!!!如果算出哪一步的 a i a_i ai大於上一步的 a i − 1 a_{i-1} ai−1,也不可以!!!!!
C++代碼
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
ll d[200005], n;
int main()
{
ios::sync_with_stdio(false);
int t; cin>>t;
while(t--)
{
cin>>n;
for(ll i=1;i<=n*2;i++)
cin>>d[i];
sort(d+1,d+2*n+1,[](ll x,ll y)->bool{
return x>y;}); //從大到小排序
bool flag = true;
for(ll i=1;i<=n*2-1;i+=2) //我沒有去重!!!只判斷了
{
if(d[i]%2 || d[i]!=d[i+1]) flag = false; //必須兩兩一組出現,而且得是偶數
}
if(d[1]%(n*2)!=0) flag = false;
ll pre = d[1]/n, cnt = 2*n, last = d[1]/n; //已經加的,剩餘個數,上一個a[i]的二倍
for(ll i=3;i<=2*n-1 && flag;i+=2)
{
cnt-=2; //剩餘數字個數-2
d[i] -= pre;
//cout<<a[i]<<endl;
flag &= (d[i]>0);
flag &= (d[i]%cnt==0);
pre += d[i]/cnt*2; //已經求過的數之和
ll now = d[i]/cnt*2; //這一個a[i]的二倍
flag &= (now<last); //a數組必須嚴格單調遞減
//cout<<last<<" "<<now<<endl;
last = now;
}
if(flag) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}