题目
给定N个整数A1, A2, ... AN。请你从中选出K个数,使其乘积最大。
请你求出最大的乘积,由于乘积可能超出整型范围,你只需输出乘积除以1000000009的余数。
注意,如果X<0, 我们定义X除以1000000009的余数是负(-X)除以1000000009的余数。
即:0-((0-x) % 1000000009)输入格式第一行包含两个整数N和K。以下N行每行一个整数Ai。
对于40%的数据,1 <= K <= N <= 100
对于60%的数据,1 <= K <= 1000
对于100%的数据,1 <= K <= N <= 100000 -100000 <= Ai <= 100000输入格式
第一行包含两个整数N和K。
以下N行每行一个整数Ai。
对于40%的数据,1 <= K <= N <= 100
对于60%的数据,1 <= K <= 1000
对于100%的数据,1 <= K <= N <= 100000 -100000 <= Ai <= 100000
评测已经全部AC
题后分享
刚开始看到这个题目的时候以为很简单,就排了序然后取最大的,最后做完发现这道题也是有坑的,要考虑的方面也很多,稍微仔细看下,还是很容易理解的,下面来讲解该怎么做这一题。
解析
根据所给序列寻找最大乘积一共有10种不同的找法,认真看其实并不难,找法很简单而且易懂,下面说一说有哪10种
- N个数全为正 取奇数个
- N个数全为正 取偶数个
- N个数全为负 取奇数个
- N个数全为负 取偶数个
- N个数中一个正数多个负数 取奇数个
- N个数中一个正数多个负数 取偶数个
- N个数中一个负数多个正数 取奇数个
- N个数中一个负数多个正数 取偶数个
- N个数中多个正数多个负数 取奇数个
- N个数中多个正数多个负数 取偶数个
在写程序的时候把每一种可能都写到程序里,自然就是一个无bug的程序。
将输入的N个数据保存到长度为N的a数组中,不管是哪一个可能,都要先对a数组进行升序排序,下面讲讲每一种可能应该怎么去找最大乘积
- N个数全为正,取奇数个,直接从a数组后面取K个数
- N个数全为正,取偶数个,直接从a数组后面取K个数
- N个数全为负,取奇数个,直接从a数组后面取K个数
- N个数全为负,取偶数个,直接从a数组前面取K个数
- N个数中一个正数多个负数,取奇数个,从a数组前面取K-1个数,a数组后面取一个数
- N个数中一个正数多个负数,取偶数个,直接从a数组前面取K个数
- N个数中一个负数多个正数,取奇数个 ,直接从a数组后面取K个数
- N个数中一个负数多个正数,取偶数个 ,直接从a数组后面取K个数
- N个数中多个正数多个负数,取奇数个,先把最大的那个正数a[n-1]留着,接着头与尾两两比较,乘积大的选取,乘积小的不选取,选取完第K-1个时,即可停止,最后一个选a[n-1],看下面的代码会比较好理解些!
- N个数中多个正数多个负数,取偶数个,头与尾两两比较,乘积大的选取,乘积小的不选取,直到选取K个
讲一个该题目挖的坑,因为-100000<=Ai<=100000 Ai*Ai最大可达到10的11次方,已经超过了int型的范围,所以a数组要用long型,下面直接上代码。
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = sc.nextInt();
long[] num = new long[k];
long[] a = new long[n];
for (int i = 0; i < n; i++)
a[i] = sc.nextInt();
Arrays.sort(a);
//负数个数
int countfu = 0;
for (int i = 0; i < n; i++)
if (a[i] < 0)
countfu++;
//正数个数
int countz = n - countfu;
//全为正(取奇/偶数个)、全为负且取奇数个、一负多正(取奇/偶数个)、
if (countfu == 0 || countfu == n && k % 2 == 1 || countfu == 1)
for (int i = 0; i < k; i++)
num[i] = a[n - 1 - i];
//全为负且取偶数个、一正多负且取偶数个
if (countfu == n && k % 2 == 0 || countz == 1 && k % 2 == 0) {
for (int i = 0; i < k; i++)
num[i] = a[i];
}
//一正多负且取奇数个
if (countz == 1 && k % 2 == 1) {
num[0] = a[n - 1];
for (int i = 1; i < k; i++)
num[i] = a[i - 1];
}
//多正多负且取偶数个(两两一对,按对取)
if (countz > 1 && countfu > 1 && k % 2 == 0) {
int i = 0, j = n - 1, x = 0;
for (int p = 0; p < k / 2; p++) {
if (a[i] * a[i + 1] > a[j] * a[j - 1]) {
num[x++] = a[i++];
num[x++] = a[i++];
} else {
num[x++] = a[j--];
num[x++] = a[j--];
}
}
}
//多正多负且取奇数个(先把最大的正数留出来)
if (countz > 1 && countfu > 1 && k % 2 == 1) {
int i = 0, j = n - 2, x = 0;
for (int p = 0; p < k / 2; p++) {
if (a[i] * a[i + 1] > a[j] * a[j - 1]) {
num[x++] = a[i++];
num[x++] = a[i++];
} else {
num[x++] = a[j--];
num[x++] = a[j--];
}
}
num[x] = a[n - 1];
}
long res = 1;
for (int i = 0; i < k; i++) {
res *= num[i];
res %= 1000000009;
}
System.out.println(res);
}
}
这道题目说难也不难,说简单也不简单,考虑的方面比较多,欢迎大家在下面留言,有问必答,大家继续努力吧!