整数集合划分(无脑贪心,很快啊!就AC了。) (使用三种语言)

题目描述

给定一个包含 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 2N105,

保证集合中各元素以及所有元素之和小于 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]));
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_46339668/article/details/113173033