UVA 10747 - Maximum Subsequence(贪心+细节)

Problem H
Maximum Subsequence

Input: Standard Input

Output: Standard Output

Time Limit: 2 Second

 

You are given a sequence of integers, each of which is not greater than 10,000 considering absolute value. There are (NCK) sub-sequences possible from this sequence. You have to pick such a subsequence, so that multiplication of all its integers is maximum.

 

For example, if the sequence is 4, 4, -4, -4 and you are asked to pick 2 integers. You have 2 ways, which will satisfy the criterion. One is to pick 4,4 and the other is to pick –4, -4.

In this case, you have to consider the sub sequence whose summation of all integers is maximum.

 

Input

The input file contains several sets of inputs. The description of each set is given below.

 

Each input set starts with 2 positive integers N, K (1<=K<=N<=10000). Next N non-empty lines contain N integers in total.

 

Input is terminated by a case where N=0 and K=0. This case should not be processed. There will be at most 60 test cases.

 

Output

For each set of input print in a single line the summation of the integers in the desired subsequence.

 

Sample Input                               Output for Sample Input

4 4

1

2

3

4

4 1

1

2

3

4

4 2

4
4
–4
–4
0 0

10

4

8



题意:给定n个数字,中选出k个数字,使得乘积最大,如果有乘积相同的,就要和最大的。

思路:贪心,按数字绝对值从大到小排,相同按正数排前面,从头选k个数字,如果选到0,说明乘积始终为0,那么只要选最大的k个就可以了,如果这些数字负数个数为偶数个,乘积>0是最优,如果为奇数个。则要考虑:去掉一个正数换后面最大的负数,去掉一个负数换后面最大的正数。两种情况比较乘积和总和,不过要注意,如果换到的是0的话要特殊考虑,并且在比较乘积的时候,整个乘积是保存不下来的,注意对于一次替换。sum = sum / m*  z。这样只要保存下m和z就可以比较了,细节比较多,写得有点搓。

代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#define max(a,b) (a)>(b)?(a):(b)
#define INF 0x3f3f3f3f
using namespace std;

const int N = 10005;

int n, k, seq[N];
bool cmp(int a, int b) {
	if (abs(a) != abs(b))
		return abs(a) > abs(b);
	return a > b;
}

void init() {
	for (int i = 0; i < n; i++)
		scanf("%d", &seq[i]);
}

int solve() {
	int sum = 0, fn = 0;
	sort(seq, seq + n, cmp);
	for (int i = 0; i < k; i++) {
		sum += seq[i];
		if (seq[i] < 0) fn++;
	}
	if (fn % 2) {
		int sum1 = -INF, sum2 = -INF, m1, z1, m2, z2;
		for (int i = k - 1; i >= 0; i--) {
			if (sum1 != -INF && sum2 != -INF) break;
			if (seq[i] > 0 && sum1 == -INF) {
				for (int j = k; j < n; j++) {
					if (seq[j] < 0) {
						sum1 = sum - seq[i] + seq[j];
						m1 = abs(seq[i]); z1 = abs(seq[j]);
						break;
					}
				}
			}
			else if (seq[i] < 0 && sum2 == -INF) {
				for (int j = k; j < n; j++) {
					if (seq[j] >= 0) {
						sum2 = sum - seq[i] + seq[j];
						m2 = abs(seq[i]); z2 = abs(seq[j]);
						break;
					}
				}
			}
			else if (seq[i] == 0) {
				sort(seq, seq + n);
				sum = 0;
				for (int i = n - 1; i >= n - k; i--)
					sum += seq[i];
				return sum;
			}
		}
		if (z2 == 0 && sum1 == -INF) {
			sort(seq, seq + n);
			sum = 0; int flag = 0;
			for (int i = n - 1; i > n - k; i--) {
				if (seq[i] == 0) flag = 1;
				sum += seq[i];
			}
			if (flag)
				sum += seq[n - k];
			return sum;
		}
		if (sum1 == -INF && sum2 == -INF) {
			sum = 0; for (int i = n - 1; i >= n - k; i--)
				sum += seq[i];
			return sum;
		}
		else if (sum1 == -INF && sum2 != -INF) return sum2;
		else if (sum1 != -INF && sum2 == -INF) return sum1;
		if (z1 * m2 == z2 * m1) sum = max(sum1, sum2);
		else if (z1 * m2 > z2 * m1) sum = sum1;
		else sum = sum2;
		
	}
	else {
		if (seq[k - 1] == 0) {
			sort(seq, seq + n);
			sum = 0;
			for (int i = n - 1; i >= n - k; i--)
				sum += seq[i];
		}
	}
	return sum;
}

int main() {
	while (~scanf("%d%d", &n, &k) && n + k) {
		init();
		printf("%d\n", solve());
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值