acwing1239.乘积最大(c++,贪心,双指针,模运算)

该博客主要讨论如何从给定的一组整数中选择K个数,使得它们的乘积最大。这个问题涉及到数论和算法优化,核心是处理负数的情况。博主提出了一种双指针策略,通过对排序后的数组进行遍历,根据负数的奇偶性来决定选取策略,以确保获得最大的乘积。同时,博主还考虑了结果可能超出整型范围的情况,给出了取模运算的处理方式。
摘要由CSDN通过智能技术生成

给定 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;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值