第九届蓝桥杯乘积最大C语言,2018省赛第九届蓝桥杯真题C语言B组第十题题解 乘积最大...

标题:乘积最大

给定N个整数A1, A2, ... AN。请你从中选出K个数,使其乘积最大。

请你求出最大的乘积,由于乘积可能超出整型范围,你只需输出乘积除以1000000009的余数。

注意,如果X<0, 我们定义X除以1000000009的余数是负(-X)除以1000000009的余数。

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

【输入格式】

第一行包含两个整数N和K。

以下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

资源约定:

峰值内存消耗(含虚拟机) < 256M

CPU消耗  < 1000ms

思路:这题我觉得贪心分情况即可:先按照绝对值从大到小排序

①假如选的k个数中必定有0,则结果为0

②假如都是负数,此时若k为偶数,则选前k个数即可,若k为奇数,则只能从小的开始选k个数

③假如都为正数,选前k个数即可

④假如正负都有,此时,若前k个数有偶数个负数,则选前k个数即可

若前k个数有奇数个负数,则我们看看能不能从后面选一个大正数跟前面的小负数做交换,或者从后面选一个大负数跟前面的小正数做交换,二者取结果大的.

此时分完所有情况若结果还为负数,我们看看输入是否有0,有零结果即为0,否则就只能输出这个负数了.

代码:

#include

#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::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<

return 0;

}

cout<

return 0;

}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值