鄙人不才,此中鄙陋甚多,望海涵!!!
题目大意:有一个长度为2*n
的a
数组,其中每个数都不相同,但这个数组每有一个正的ai
就对应有一个负的aj
,但现在忘掉了这个数组a,之依稀记得数组d,数组d是di=∑(j从1~n)|ai−aj|
,但因为是依稀记得,所以这个a可能存在,也可能不存在,如果存在输出YES,否则输出NO
题目分析:对于d我们可以做一些研究,因为差值总是成对存在,以此每个d必须是正偶数,而我们又知道正数a和负数a到其他点的距离相等,所以这个d还需要成对儿存在,然后由于每个a都是不同的,因此每个d也是不同的,(顺带一提肯定是中位数对应的d最小,边界的a对应的d最大)简单的前提条件搞定了,那我们就需要画数轴具体分析d的规律!
我们来举一个具体的序列 -1 1 -5 5 -7 7,由于正负一样,我们只研究正数
1对应的d为 2*(1+5+7)
5对应的d为 2*(5+5+7)
7对应的d为 2*(7+7+7)
我们不难发现,其实对与最后的d我们可以算出来当前对应a,而有了这个a我们就可以算出来前面的那个d对应的a,利用前缀和我们可以快速得到这些a,只要计算过程中我们的a是正整数就行,否则不行!
C++Code
#include<iostream>
#include<map>
#define int long long
using namespace std;
const int N=1e5+10;
int sum[N],s,cnt;
map<int,int> mp;
signed main()
{
int T;
cin>>T;
while(T--)
{
cnt=s=0;
mp.clear();
int n;
cin>>n;
bool suc=true;
for(int i=0;i<2*n;i++)
{
int x;
scanf("%lld",&x);
if(x&1 || x<=0) suc=false;//判断d是不是正偶数
mp[x]++;
}
if(suc)
{
for(auto x:mp)
{
if(x.second!=2)//判断d是不是成对存在
{
suc=false;
break;
}
sum[++cnt]=x.first;//有序保存d,顺带一提如果合法cnt==n
}
if(suc)
{
for(int i=cnt;i>=1;i--)
{
sum[i]/=2;
//这里s就是前缀和,检测d对应的a是否为正整数
if((sum[i]-s)%i==0 && (sum[i]-s)/i>0) s+=(sum[i]-s)/i;
else
{
suc=false;
break;
}
}
}
}
if(suc) puts("YES");
else puts("NO");
}
return 0;
}