给定 N 个整数 A1,A2,…AN。
请你从中选出 K 个数,使其乘积最大。
请你求出最大的乘积,由于乘积可能超出整型范围,你只需输出乘积除以 1000000009 的余数。
注意,如果 X<0, 我们定义 X 除以 1000000009 的余数是负(−X)除以 1000000009 的余数,即:0−((0−x)%1000000009)
输入格式
第一行包含两个整数 N 和 K。
以下 N 行每行一个整数 Ai。
输出格式
输出一个整数,表示答案。
数据范围
1≤K≤N≤105,
−105≤Ai≤105
输入样例1:
5 3
-100000
-10000
2
100000
10000
输出样例1:
999100009
输入样例2:
5 3
-100000
-100000
-2
-100000
-100000
输出样例2:
-999999829
难度:中等
时/空限制:1s / 64MB
总通过数:2462
总尝试数:8042
来源:第九届蓝桥杯省赛C++B组
算法标签
下面展示一些 内联代码片
。
/*
冷知识:c++中取模(%)运算的结果的符号是和操作数1的符号保持一致,这里是负数除一个整数的余数
刚好是负数,与c++中%法则相同,所以这里不需要特殊处理
思路:求n个数中k个数最大乘积总体思路:全是正数,选最大的k个数;若有复数,让负数成对出现(负负得正)
步骤:A.先对n个数进行排序(按真实数据排序即可)
排序完会发现,两边往中间的绝对值是减少的,即两边的绝对值最大(正负数都是)
类似归并排序思想,这里用双指针,从最两端开始。
B.分类:1.k==n时候,全选
2.k<n时候:21.k为偶数,结果必然为非负
211.负数有偶数个(结果必然为正数)
212.负数有奇数个(不选绝对值最小的那个负数即可)
22.k为奇数
221.所有数据均是负数,结果必然为负数
222.至少存在一个非负数,结果必然为非负数(选k-1(偶数)个负数)
*/
#include"iostream"
#include"algorithm"
#include"cstdio"
using namespace std;
typedef long long LL;
const int N=100010;
int n,k;
LL mod=1000000009;
int a[N];
int main(){
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++)scanf("%d",&a[i]);
sort(a,a+n); //先对n个数进行排序
int res=1; //存结果
int l=0,r=n-1; //双指针初始化
int sign=1; //标记符号
if(k%2){ //k为奇数
res=a[r--]; //k为奇数,先取最大的数,然后正数偶数取偶数个(222)
if(res<0)sign=-1; //取最右边的数,小于0即表明全为负数,结果为负数
k--; //此时再取k-1即可
}
while(k){
LL x=(LL)a[l]*a[l+1],y=(LL)a[r]*a[r-1];
if(x*sign>y*sign){
res=x%mod*res%mod;
l+=2;
}
else {
res=y%mod*res%mod;
r-=2;
}
k-=2;
}
cout<<res<<endl;
return 0;
}