CSDN算法技能树-蓝桥杯-简单-2.15 乘积最大

文章讲述了计算给定整数数组中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

A:正确

int main()
{
    int n, k;
    long long ans;
    cin >> n >> k;
    vector<long long> num;
    for (int i = 0; i < n; i++)
    {
        int temp;
        cin >> temp;
        num.push_back(temp);
    }
    sort(num.begin(), num.end());//升序排列 1 2 3 4 5 ...
    if (k % 2 != 0)  //判断k是奇数还是偶数 
    {
        ans = num.back(); //将最后一位给ans并出栈
        k = k - 1;
        num.pop_back();
    }
    else
        ans = 1;
    while (k > 0)//把最大的两个数的乘积给ans,然后再循环比较,相乘
    {
        if ((num[0] * num[1]) > num.at(num.size() - 1) * num.at(num.size() - 2))
        {
            ans = ans * num[0] * num[1] % 1000000009;
            num.erase(num.begin(), num.begin() + 1);
        }
        else
        {
            ans = ans * num.at(num.size() - 1) * num.at(num.size() - 2) % 1000000009;
            num.pop_back();
            num.pop_back();
        }
        k -= 2;
    }
    cout << ans;
    return 0;
}

 B:错误,原因:元素下标不对应

#define ll long long
#define inf 0x7fffffff
const int N = 1e5 + 10; // 1*10^5 + 10
const int mod = 1e9 + 9;
int n, k;
int a[N];
ll ans = 1;
int main()
{
    cin >> n >> k;
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);

    sort(a + 1, a + n + 1); //因为i是从1开始的,故为a+1, 第二项由函数定义可知,需为尾元素地址的下一个地址故为 a+n+1

    int sign = 1;
    if (k % 2) //判断k的奇偶
    {
        ans = a[n];
        n--;
        k--;
    }

    int i = 0, j = n; //错在这里,在输入的时候是从1开始的,而这里却是从0开始的
    while (k)//和A一样
    {
        ll tmp1 = (ll)a[i] * a[i + 1], tmp2 = (ll)a[j] * a[j - 1];
        if (tmp1 * sign > tmp2 * sign)
        {
            ans = (tmp1 % mod * ans) % mod;//他为什么要这么写呢?这也是我的第一个问题,感觉就和(tmp * ans)% mod 一样
            i += 2;
        }
        else
        {
            ans = (tmp2 % mod * ans) % mod;
            j -= 2;
        }
        k -= 2;
    }

    printf("%lld\n", ans);
    return 0;
}

C:正确

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std; 
#define mod 1000000009
const int N = 100010;
typedef long long LL;
int a[N];
int n, k;
int main()
{
    cin >> n >> k;
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &a[i]);
    }
    sort(a, a + n);
    LL res = 1;
    //这里采用分布式的方法,分别判断k与n的关系,并各自做出反应
    if (n == k)
    {
        for (int i = 0; i < n; i++)
        {
            res = (res * a[i]) % mod;
        }
        cout << res % mod;
        return 0;
    }

    if (a[n - 1] < 0)    //全负
    {
        if (k % 2 == 1)
        {
            for (int i = n - 1; i >= n-k; i--)  
            {
                res = (res * a[i]) % mod;
            }
        }
        else
        {
            for (int i = 0; i < k; i++)
            {
                res = (res * a[i]) % mod;
            }
        }
        cout << res << endl;
        return 0;
    }

    int l = 0, r = n - 1;
    if (k % 2 == 1)        //有正有负
    {
        res = a[r--];
        k--;
    }
    while (k)
    {
        LL x = (LL)a[l] * a[l + 1], y = (LL)a[r] * a[r - 1];
        if (x > y)
        {
            res = x % mod * res % mod;
            l += 2;
        }
        else
        {
            res = y % mod * res % mod;
            r -= 2;
        }
        k -= 2;
    }
    cout << res << endl;
    return 0;
}

D:正确

#include <iostream>
#include <algorithm>
#include <map>
using namespace std;


#define mem(a, b) memset(a, b, sizeof(a))
#define mod 1000000009

typedef long long ll;
const int maxn = 1e6 + 5;
const double esp = 1e-7;
const int ff = 0x3f3f3f3f;
map<int, int>::iterator it;

struct node
{
    ll x;
    int f;
} a[maxn];

int n, k;

bool cmp(node x, node y)
{
    return x.x > y.x;
}

ll solve(int o)  
{
    ll ans = 1;
    int cnt = 0;
    if (o == 0)
    {
        for (int i = 1; i <= k; i++)
        {
            ans = (ans * a[i].x) % mod;
            if (a[i].f == 1)
                cnt++;
        }
    }
    else
    {
        for (int i = n; i > n - k; i--)
        {
            ans = (ans * a[i].x) % mod;
            if (a[i].f == 1)
                cnt++;
        }
    }

    if (cnt & 1)
        return ans * (-1);
    return ans;
}

int main()
{
    cin >> n >> k;

    int flag = 0;
    int cnt = 0;
    for (int i = 1; i <= n; i++)
    {
        scanf("%lld", &a[i].x); 
        if (a[i].x < 0)  //如果是负数,就给f赋值为1且将其转为正数 
        {
            a[i].f = 1;
            a[i].x = -a[i].x;
            cnt++;
        }
        else if (a[i].x > 0)
            a[i].f = 0;
        else          //等于0的话,就让下一个数将其覆盖
        {
            i--;
            n--;
            flag = 1;
        }
    }

    sort(a + 1, a + n + 1, cmp); //倒序排列

    ll ans = 0;

    if (n < k)
        ans = 0;
    else if (cnt == n)      //全是负数
    {
        if (k & 1)//判断k的奇偶
            ans = solve(1);
        else
            ans = solve(0);
    }
    else if (cnt == 0)      //全是正数
        ans = solve(0);
    else                    //有正有负
    {
        int tmp = 0;
        for (int i = 1; i <= k; i++) //判断前面最大的几个数里面有几个负数用tmp记录
            if (a[i].f == 1)
                tmp++;

        if (tmp % 2 == 0)   //偶数个
            ans = solve(0);
        else                //奇数个
        {
            ans = -1;

            int p = -1, q = -1;
            for (int i = k + 1; i <= n; i++) //在a[k+1]~a[n]之间找最大的正数
                if (a[i].f == 0)
                {
                    q = i;
                    break;
                }
            for (int i = k; i >= 1; i--)    //在a[1]~a[k]之间找负数
                if (a[i].f == 1)
                {
                    p = i;
                    break;
                }

            if (p != -1 && q != -1) //找到了
            {
                swap(a[p], a[q]); 
                ans = solve(0);
                swap(a[p], a[q]);
            }

            p = -1, q = -1;
            for (int i = k + 1; i <= n; i++) //找这个范围里面的负数
                if (a[i].f == 1)
                {
                    q = i;
                    break;
                }
            for (int i = k; i >= 1; i--)  //找正数
                if (a[i].f == 0)
                {
                    p = i;
                    break;
                }

            if (p != -1 && q != -1)
            {
                swap(a[p], a[q]);
                ans = max(ans, solve(0));
                swap(a[p], a[q]);
            }

            if (ans < 0)
                ans = solve(1);
        }
    }

     if (ans < 0)
        if (flag)
        {
            cout << 0 << endl;
            return 0;
        }
    cout << ans << endl;

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值