2018年第九屆藍橋杯【C++省賽B組】【第十題:乘積最大】——貪心算法,附解題源碼

2018年第九屆藍橋杯題目彙總

https://blog.csdn.net/qq_34202873/article/details/79784728


第十題

標題:乘積最大

給定N個整數A1, A2, … AN。請你從中選出K個數,使其乘積最大。

請你求出最大的乘積,由於乘積可能超出整型範圍,你只需輸出乘積除以1000000009的餘數。

注意,如果X<0, 我們定義X除以1000000009的餘數是負(-X)除以1000000009的餘數。

即:0-((0-x) % 1000000009)

【輸入格式】
第一行包含兩個整數NK。  
以下N行每行一個整數Ai。  

對於40%的數據,1 <= K <= N <= 100  
對於60%的數據,1 <= K <= 1000  
對於100%的數據,1 <= K <= N <= 100000  -100000 <= Ai <= 100000  

【輸出格式】
一個整數,表示答案。
【輸入樣例】
5 3 
-100000   
-10000   
2   
100000  
10000  

【輸出樣例】
999100009
再例如:
【輸入樣例】
5 3 
-100000   
-100000   
-2   
-100000  
-100000

【輸出樣例】
-999999829

解題思路:

先按照絕對值從大到小排序

①假如選的k個數中必定有0,則結果爲0

②假如都是負數,此時若k爲偶數,則選前k個數即可,若k爲奇數,則只能從小的開始選k個數

③假如都爲正數,選前k個數即可

④假如正負都有,此時,若前k個數有偶數個負數,則選前k個數即可

若前k個數有奇數個負數,則我們看看能不能從後面選一個大正數跟前面的小負數做交換,或者從後面選一個大負數跟前面的小正數做交換,二者取結果大的.

此時分完所有情況若結果還爲負數,我們看看輸入是否有0,有零結果即爲0,否則就只能輸出這個負數了.

代碼

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define mod 1000000009
using namespace std;
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)
        {
            a[i].f = 1;
            a[i].x = -a[i].x;
            cnt++;
        }
        else if(a[i].x> 0)
            a[i].f = 0;
        else
        {
            i--;n--;//我們不記錄0,0只做迫不得已的選擇 
            flag = 1;
        }
    }

    sort(a+1,a+n+1,cmp);

    ll ans = 0;

    if(n< k)//如果必須選0 
        ans = 0;
    else if(cnt == n)//如果都爲負數 
    {
        if(k&1)
            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++)
            if(a[i].f == 1)
                tmp++;

        if(tmp%2 == 0)//如果前k大的數有偶數個負數 
            ans = solve(0);
        else
        {
            ans = -1;//將其設置爲負數 
            //嘗試將前k個裏面一個絕對值最小負數和後面最大正數交換 
            int p = -1,q = -1;
            for(int i = k+1;i<= n;i++)
                if(a[i].f == 0)
                {
                    q = i;
                    break;
                }
            for(int i = k;i>= 1;i--)
                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]);
            }

            //嘗試將前k個裏面一個最小正數和後面絕對值最大正數交換
            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]);
            }

            //假如結果仍然小於0,我們只能嘗試從最後往前乘了 
            if(ans< 0)
                ans = solve(1); 
        }
    }

    if(ans< 0)
        if(flag)//這時候0派上用場了 
        {
            cout<<0<<endl;
            return 0;
        }
    cout<<ans<<endl;

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章