UVa 10747 - Maximum Subsequence (贪心 + 细节)

题意

从N个数中选出K个数,使得乘积最大,如果有相同的乘积,输出最大的和

思路

最基本的思路,很好想。先按照绝对值排一下序,从头开始选K个,如果有奇数个负数,要么换一个负数,要么换一个正数。

然后就是细节的处理。然后我就像挤牙膏一样写了三个小时( TДT)( TДT)

导致代码无比得丑

先让我缓一下。等下再来写细节

代码

#include <cstdio>
#include <stack>
#include <set>
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <functional>
#include <cstring>
#include <iomanip>
#include <algorithm>
#include <cctype>
#include <string>
#include <map>
#include <cmath>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define SZ(x) (int)x.size()
#define Lowbit(x) ((x) & (-x))
#define MP(a, b) make_pair(a, b)
#define MS(arr, num) memset(arr, num, sizeof(arr))
#define PB push_back
#define F first
#define S second
#define ROP freopen("input.txt", "r", stdin);
#define MID(a, b) (a + ((b - a) >> 1))
#define LC rt << 1, l, mid
#define RC rt << 1|1, mid + 1, r
#define LRT rt << 1
#define RRT rt << 1|1
#define BitCount(x) __builtin_popcount(x)
#define BitCountll(x) __builtin_popcountll(x)
#define LeftPos(x) 32 - __builtin_clz(x) - 1
#define LeftPosll(x) 64 - __builtin_clzll(x) - 1
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
const int MAXN = 10000 + 10;
const int MOD = 1000007;
const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
typedef pair<int, int> pii;
typedef vector<int>::iterator viti;
typedef vector<pii>::iterator vitii;
 
struct NUMBER
{
    int val, sign;
    bool operator < (const NUMBER &a) const
    {
        if (val != a.val) return val > a.val;
        return sign > a.sign;
    }
}arr[MAXN];
 
int n, k;
 
bool Exclude(int ans)
{
    int i, minNeg = INF;
    for (i = 0; i < k; i++)
    {
        if (arr[i].sign < 0) minNeg = min(minNeg, arr[i].val * arr[i].sign);
        if (arr[i].sign > 0) return false;
    }
    if (i == k)
    {
        int rpls = -INF;
        for (int j = k; j < n; j++)
            if (arr[j].sign > 0) return false;
        int kans = 0;
        for (i = n - 1; i > n - 1 - k; i--) kans += arr[i].sign * arr[i].val;
        printf("%d\n", kans);
        return true;
    }
}
 
void Solve()
{
    sort(arr, arr + n);
    if (n == k)     //如果nk相等,只能全部选上
    {
        int ans = 0;
        for (int i = 0; i < n; i++) ans += arr[i].val * arr[i].sign;
        printf("%d\n", ans);
        return;
    }
    int cntNegative = 0, minPositiveNumber = INF, maxNegativeNumber = -INF, ans = 0;
    bool flag = false;
    for (int i = 0; i < k; i++)
    {
        ans += arr[i].val * arr[i].sign;
        if (arr[i].val == 0) flag = true;
        if (arr[i].val * arr[i].sign < 0)
        {
            cntNegative++;
            maxNegativeNumber = max(maxNegativeNumber, arr[i].val * arr[i].sign);
        }
        else if (arr[i].val > 0) minPositiveNumber = min(minPositiveNumber, arr[i].val);
    }
    int maxPosSel = -INF, minNegSel = INF;
    for (int i = k; i < n; i++)
    {
        if (arr[i].val * arr[i].sign >= 0) maxPosSel = max(maxPosSel, arr[i].val * arr[i].sign);
        if (arr[i].val * arr[i].sign < 0) minNegSel = min(minNegSel, arr[i].val * arr[i].sign);
    }
    if ((cntNegative & 1) || flag == true)
    {
        if (arr[k].val == 0)
        {
            int kans = 0, cnt = 0;
            for (int i = 0; i < k; i++)
                if (arr[i].sign > 0)
                {
                    cnt++;
                    kans += arr[i].val;
                }
            cnt = k - cnt;
            for (int i = n - 1; cnt; i--)
                if (arr[i].sign <= 0)
                    kans += -arr[i].val, cnt--;
            printf("%d\n", kans);
        }
        else if (Exclude(ans)) return;
        //这时候要选择换掉负数还是换掉正数
        //如果后面没正数可以顶掉换下的负数,只能换正数
        else if (maxPosSel == -INF)
            printf("%d\n", ans - minPositiveNumber + minNegSel);
        //没负数可以顶掉换下的正数,只能换负数
        else if (minNegSel == INF || minPositiveNumber == INF)
            printf("%d\n", ans - maxNegativeNumber + maxPosSel);
        else if (maxPosSel * minPositiveNumber < minNegSel * maxNegativeNumber)
            printf("%d\n", ans - minPositiveNumber + minNegSel);
        else if (maxPosSel * minPositiveNumber >= minNegSel * maxNegativeNumber)
            printf("%d\n", ans - maxNegativeNumber + maxPosSel);
    }
    else printf("%d\n", ans);
}
 
int main()
{
    //ROP;
   // freopen("myout.txt", "w", stdout);
    int i, j;
    while (scanf("%d%d", &n, &k), n + k)
    {
        for (i = 0; i < n; i++)
        {
            int tmp;
            scanf("%d", &tmp);
            if (tmp < 0)
            {
                arr[i].val = -tmp;
                arr[i].sign = -1;
            }
            else if (tmp > 0)
            {
                arr[i].val = tmp;
                arr[i].sign = 1;
            }
            else
            {
                arr[i].val = 0;
                arr[i].sign = 0;
            }
        }
        Solve();
    }
    return 0;
}

Powered by Jekyll and Theme by solid