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

    思路:

        因为这个对称性得特性,并且2n个数字是不一样得,那么我们就能从这里入手,按照绝对值来讲,a[i] = -a[j]得话,那么d[i] = d[j],并且a数组里面不能有0,因为有零就需要另一个零和他配对,成为对称数组。

        那么,给出来得d数组就能够有了一个限制:得到得每一个数字有且仅有两个。(因为上面得d[i]=d[j])。

        这个j是没有位置限制得,那么我们就把a数组从小到大排序,只要求出来正得那一半得a[i](1<=i<=n)那么就说明是可以得到a数组得,就输出yes

        说完yes了,那么有没有可能又出现No得可能呢。答案是当然得,因为这个a有可能是求不到的。既然这样,那么就需要知道如何求出来每一个a[i]了(正得)。

        从小到大对啊a[i]进行排序(假设a存在),a[1]、a[2]、……a[n]  …… -a[1]……-a[n],那么,我们来推断a得通式吧!

        d[i] = (a[i]-a[1] + a[i] - a[2] + …… +a[i] - a[i] + a[i+1]-a[i] + a[i+2] - a[i]+ …… +a[n] - a[i])+(a[i]+a[1] + a[i]+a[2]+……+a[i]+a[n])

        d[i] = (i*a[i]-si+sn-si-(n-i)*a[i]) +(n*a[i]+sn) =  2*(i*a[i]-si+sn),这样子a[i]就有了,a[i] = d[i]-2*(sn-si)/2*i,那么这个sn-si怎么求呢,那么很特殊得a[n]=d[n]/2*i,那么s[n]-s[i]不是手到擒来了。(sn表示a1+……+an)。

        那么从后向前求a[i]就可以啦,如果a[i]求出来是分数,那么这个a是不存在,这就是d得另一个限制

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
void solve(){
    int n;
    cin >> n;
    int a[2*n+2];
    int flag = 0;
    for(int i = 1;i <= 2 * n; i++) {
        cin >> a[i];
        if(a[i] & 1){
            flag = 1;//其实是第二个限制
        }
    }
    sort(a+1,a+2*n+1);


    int b=a[1];
    int cnt = 0;//第一个限制
    for(int i = 1;i<=2*n;i++){
    	if(a[i]==b){
    		cnt++;
		}
		else{
			if(cnt !=2){
    			cout << "NO\n";
    			return ;
			}
			cnt=1;
			b=a[i];
		}
	}
	if(cnt != 2) {
		cout << "No\n";
		return ;
	}
    vector<int> d;
    for(int i = 1;i<=2*n;i+=2){
        d.push_back(a[i]);
    }
    sort(d.begin(),d.end());
    if(flag){
        cout << "NO\n";
        return ;
    }


    int sum[n+2]={0};


    for(int i = n-1;i >=0;i --){//第二个限制
    	if((d[i]-2*sum[i+1])<=0) {
    		cout << "NO\n";
    		return ;
		}
        if((d[i]-2*sum[i+1])%(2*(i+1))) {
            cout << "NO\n";
            return ;
        }


        sum[i]=sum[i+1]+(d[i]-2*sum[i+1])/(2*(i+1));//这个就是s[n]-s[i]因为是从后向前面求,所以是sum[i+1]+a[i],后面一大堆是a[i]。
    }


    cout << "YES\n";//两道限制都过了,直接yes
    
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while(t--){
        solve();
    }
    return 0;
} 

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值