AcWing寒假每日一题——Day18整数集合的划分

整数集合的划分:

给定一个包含 N N N 个正整数的集合,请你将它划分为两个集合 A 1 A_1 A1 A 2 A_2 A2,其中 A 1 A_1 A1 包含 n 1 n_1 n1 个元素, A 2 A_2 A2 包含 n 2 n_2 n2 个元素。

集合中可以包含相同元素。

S 1 S_1 S1 表示集合 A 1 A_1 A1 内所有元素之和, S 2 S_2 S2 表示集合 A 2 A_2 A2 内所有元素之和。

请你妥善划分,使得 ∣ n 1 − n 2 ∣ |n_1−n_2| n1n2 尽可能小,并在此基础上 ∣ S 1 − S 2 ∣ |S_1−S_2| S1S2 尽可能大。

输入格式
第一行包含整数 N N N

第二行包含 N N N 个正整数。

输出格式
再一行中输出 ∣ n 1 − n 2 ∣ |n_1−n_2| n1n2 ∣ S 1 − S 2 ∣ |S_1−S_2| S1S2,两数之间空格隔开。

数据范围
2 ≤ N ≤ 1 0 5 , 2≤N≤10^5, 2N105,
保证集合中各元素以及所有元素之和小于 2 31 2^{31} 231

输入样例1:

10
23 8 10 99 46 2333 46 1 666 555

输出样例1:

扫描二维码关注公众号,回复: 12453219 查看本文章

0 3611

输入样例2:

13
110 79 218 69 3721 100 29 135 2 6 13 5188 85

输出样例2:

1 9359

分析: 贪心问题。首先题目条件是首先要保证 n 1 − n 2 n_1-n_2 n1n2最小,故而要分奇偶, n n n为偶数时 n 1 − n 2 = 0 n_1-n_2=0 n1n2=0 n n n为奇数时 n 1 − n 2 = 1 n_1-n_2=1 n1n2=1。所以就是将集合对半分,找出差距最大的集合。可以排序,然后分成两部分相减就是答案了。
证明:设两个集合 S 1 = { a 1 , a 2 . . . a n 2 } , S 2 = { a n 2 + 1 . . . a n } S_1=\left \{ a_1,a_2...a_{\frac{n}{2}}\right \} ,S_2=\left \{ a_{\frac{n}{2}+1}...a_n\right \} S1={ a1,a2...a2n},S2={ a2n+1...an},假设 S 1 ≤ S 2 S_1 \le S_2 S1S2,如果 ∃ a x ∈ S 1 , a y ∈ S 2 \exist a_x\in S_1,a_{y} \in S_2 axS1,ayS2使得 a x > a y a_x>a_y ax>ay,那么如果将 a x a_x ax分给 S 2 S_2 S2 a y a_y ay分给 S 1 S_1 S1,此时两个集合的大小为 S 1 ′ = S 1 − ( a x − a y ) , S 2 ′ = S 2 + ( a x − a y ) , S_1'=S_1-(a_x-a_y),S_2'=S_2+(a_x-a_y), S1=S1(axay),S2=S2+(axay), S 2 ′ − S 1 ′ = S 2 − S 1 + 2 ( a x − a y ) > S 2 − S 1 , S_2'-S_1'=S_2-S_1+2(a_x-a_y)>S_2-S_1, S2S1=S2S1+2(axay)>S2S1,与最优解矛盾。所以 S 1 ≤ S 2 S_1 \le S_2 S1S2恒成立。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int a[N];
int main(){
    
    
    int n,res=0,sum=0;
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i],sum+=a[i];
    sort(a,a+n);
    for(int i=0;i<n/2;i++) res+=a[i];
    cout<<n%2<<" "<<sum-2*res<<endl;
}