数字的最大K-乘积

时间:2013-09-21 00:19:49

标签: c++ algorithm max product modulo

任务 - 数字的最大K-乘积
时间限制:1
记忆限制:64 M
给定一系列整数N(1≤N≤10May,| A i |≤2.109)和K的数目(1≤K≤N)。查找产品最大的K序列号。

输入数据:
第一行包含两个整数N和K. 在第二行中列出了序列A的N个元素。

输出数据:
获得最大产品。所以答案可能非常大,输出模10 ^ 9 + 7。

实施例
输入数据的结果
3 2
-2 -3 3

答案 - 6

以下是我的尝试。这是一个错误,这是我不知道的。你能否帮我在决定中找错?

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
using namespace std;
typedef vector<int> v1;
const int mod = 1000000007;
int n, k, pos1 = 0, pos2 = 0, negative = 0;
long long res = 1;
void QuickSort(v1 &a, int l, int r) {
  int i = l, j = r, pivot = abs(a[l + ((r - l) >> 1)]);
  do {
        while (abs(a[i]) < pivot) i++;
        while (abs(a[j]) > pivot) j--;
        if (i <= j) {
            int temp = a[i];
            a[i++] = a[j];
            a[j--] = temp;
        }
    } while (i < j);
    if (l < j) QuickSort(a, l, j);
    if (i < r) QuickSort(a, i, r);
}

long long product(v1 &a, v1 &b, int q, int j, char flag) {
    long long res = 1; int temppos;
    if (flag == 0 && j) {
        temppos = b[pos1];
        b[pos1] = j;
    }
    if (flag == 1 && q) {
        temppos = b[pos2];
        b[pos2] = q;
    }
    if (!pos2 && (k & 1)) {
        for (int i = 1; i <= k; i++)
            res = (long long)((res % mod)*1ll*(a[i] % mod)) % mod;
    } else {
        for (int i = 1; b[i] != 0; i++)
            res = (long long)((res % mod)*1ll*(a[b[i]] % mod)) % mod;
    }
    if (flag == 0 && j) b[pos1] = temppos;
    if (flag == 1 && q) b[pos2] = temppos;
    return res;
}

int main()
{
      v1 a(100002, 0);
        v1 b(100002, 0);  //index multiplied to the elements
        cin >> n >> k;
        for (int i = 1; i <= n; i++) cin >> a[i];
        QuickSort(a, 1, n);
        for (int i = n, j = 1; i > n - k; i--) {
                b[j] = i;
                if (a[i] < 0) {                     
                    pos1 = j;    //index last positive number 
                    negative++;  //increase the counter negative numbers
                }
                  else pos2 = j;  //index last positive number                
                j++;
        }
        int j = n - k, q = j;
        if (negative & 1) { //If an odd number of negative numbers
            while (j > 0 && a[j] < 0) j--;
            while (q > 0 && a[q] > 0) q--;
            res = max(product(a, b, q, j, 0), product(a, b, q, j, 1));
        } else res = product(a, b, q, j, 3);
        cout << res << endl;
    cin >> res;
    return 0;
}

1 个答案:

答案 0 :(得分:0)

首先:你的代码非常密集和混乱,所以我会在这里给出自己的方法和思考过程。

所以我的第一个想法是关于所有输入整数都是正数的情况。调用我们的源数组(包含N个整数的数组)A。

  • 初始化包含A中前K个元素的数组B.
  • 对于每个i,使得K <= i <= n,针对B中的每个元素检查A [i]。如果A [i]大于某个B [j],则将B [j]替换为A [i]中。
  • 完成后,将B的内容乘以模10 ^ 9 + 7。

这需要O(KN)时间,所以如果K比O(lg(N))慢,那么它比你的快速排序更快,也更简单。你可以通过使用树或堆来存储B来改善O(N lg(K))的时间限制,但这超出了职责范围。

我的解决方案的问题是该问题将负数作为输入。现在,如果通过“Answer - 6”表示“答案是-6 = -2 * 3”,并且您要求的是最大幅度的产品,那么您需要做的就是获取上面每个输入数字的大小程序。但是你的代码表明你的意思是“答案是6 = -2 * -3”,在这种情况下,事情要复杂得多。

看看,如果最大乘积包含两个(或偶数)负整数(如(6 = -2 * -3)的例子),我的方法将不起作用,因为排序程序吸收负数在列表的底部。

相反,我们需要做的是保留三个数组:A,我们的输入数组; B,到目前为止遇到的K 最大正数字的数组;和C,一个最小负数的数组(以避免混淆:在列表-2 -3 -4中,两个最小的负数是-3和-4)到目前为止遇到的数字。

当我们使用类似于上面的例程提取B和C时,我们需要将它们组合起来。我能想到的最好的方法是首先对B和C进行排序,然后

  • 计算B模10 ^ 7 + 9中所有数字的乘积。将其记录为MAX。
  • 用B中的两个最小(最负)数字替换B中的两个最小数字。
  • 再次计算B中所有数字的乘积,如果它大于当前MAX,则更新MAX。
  • 将B中两个最小的数字替换为 next 来自C的两个最小数字。
  • 重复直到你走完C。

这需要O(K ^ 2)或左右,你可以再用一个更智能的方法来加快速度(比如当你插入的负数对的乘积小于产品时停止替换)您正在替换的正数对),但这是我能想到的最清楚的数字。