题目描述
给定一个包含 N 个正整数的集合,请你将它们划分为两个不相交的集合 A1 和 A2,其中 A1 包含 n1 个元素,A2 包含 n2个元素。
用 S1表示集合 A1 内所有元素之和,S2 表示集合 A2 内所有元素之和。
请你妥善划分,使得 |n1−n2|尽可能小,并在此基础上 |S1−S2|尽可能大。
输入格式
第一行包含整数 N。
第二行包含 N个正整数。
输出格式
再一行中输出 |n1−n2|和 |S1−S2|,两数之间空格隔开。
数据范围
2 ≤ N ≤ 1 0 5 2≤N≤10^5 2≤N≤105,
保证集合中各元素以及所有元素之和小于 2 3 1 2^31 231。
输入样例1:
10
23 8 10 99 46 2333 46 1 666 555
输出样例1:
0 3611
输入样例2:
13
110 79 218 69 3721 100 29 135 2 6 13 5188 85
输出样例2:
1 9359
核心思路
题目让两个集合的元素个数之差最小,数值总和之差最大。 所以划分两个集合的思路如下:
* 对所有元素 排个序, [0,n/2] ,[n/2,n] 分别作为两个集合。
* 受前缀和的启发: 数值总和之差 = 所有元素总和 - 两倍的[0,n/2]区间的总和。
C++代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int N=100010;
int main()
{
vector<int>v;
int n,s=0,x;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&x);
v.push_back(x);
s+=x;
}
sort(v.begin(),v.end());
for(int i=0;i<n/2;i++)
{
s-=2*v[i];
}
if(n%2==0)
printf("0 %d",s);
else
printf("1 %d",s);
return 0;
}
python3 代码
if __name__ == "__main__":
n = int(input())
a = list(map(int, input().split()))
a.sort()
diff = 0
if n % 2 == 1: diff = 1
print(diff, sum(a) - 2*sum(a[:n//2]))
java 代码
import java.util.Scanner;
import java.util.Arrays;
class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] s = new int[n+1];
int[] a = new int[n+1];
for(int i = 1; i<= n;i++){
s[i] =sc.nextInt();
}
sc.close();
Arrays.sort(s);//排序
for(int i = 1;i<=n;i++){
//构造前缀和数组
a[i] = a[i-1]+s[i];
}
int mid = n/2;
if(n % 2 == 1){
System.out.print("1 "+ (a[n]-2*a[mid]));
}else{
System.out.print("0 "+ (a[n]-2*a[mid]));
}
}
}