第九届蓝桥杯省赛B组:乘积最大 C/C++解法

博客介绍了如何使用动态规划和递归法解决蓝桥杯竞赛中的一道题目,目标是找出给定整数数组中K个数的最大乘积,并考虑了数值可能为负的情况。解题思路包括计算前i项的最大值和乘积,然后通过比较选择较大的乘积进行递归计算,最终结果需对1000000009取模。

蓝桥杯:乘积最大  C/C++解法

题目描述

给定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

【输出格式】
一个整数,表示答案。


【输入样例1】

5 3
-100000
-10000
2
100000
10000

【输出样例1】

999100009

【输入样例2】

5 3
-100000
-100000
-2
-100000
-100000

【输出样例2】

-999999829

解题思路

这道题可以用DP去解决。首先,求出前 i 项中最大值以及前 i 项乘积,这样的好处是在之后的递归中可以节省时间。之后调用dp_func()函数进行乘积计算。

dp_func()函数原理:
从 n 项中选出 k 个数的最大乘积等同于
            1>从 n-1 项中选出 k 个数的最大乘积
        或 2>从 n-1 项中选出 k-1 个数的最大乘积再乘以第 n 个数
之后 1> 和 2> 比较大小,选择乘积大的作为答案        (以此类推用递归法写)

注意事项: 数字乘积比较大,用 long long 进行存储,最后求模

代码实现

#include <bits/stdc++.h> 
using namespace std;

#define MAXLEN 100009	/* 100009太大了,编译器可能报错,
						编译时改小,代码提交时要改回来 */ 
typedef long long ll;

ll a[MAXLEN];
ll dp[MAXLEN][MAXLEN];
int b[MAXLEN][MAXLEN]={0};	//标记dp[][]二维数组中项 是否被赋值  赋值后为 1  

int mod_self(ll x)  // 求余函数 
{
	if(x>=0)  return x%1000000009;
	else return (0-((0-x)%1000000009));
}


/*
len表示总数量,cat表示拿的数量   
此函数功能为求出最大乘积 
*/ 
ll dp_func(int len, int cat)	
{
	if(cat<=len) 
	{
		if(b[len][cat]) return dp[len][cat];
		else 
		{
			dp[len-1][cat-1]=dp_func(len-1,cat-1);	// 前len-1中取cat-1个数 
			
			dp[len-1][cat]=dp_func(len-1,cat);	// 前len-1中取cat个数 
			
			dp[len][cat]=1;
			if(dp[len-1][cat] > (dp[len-1][cat-1]*a[len]))
				return dp[len][cat]=dp[len-1][cat];	
			else 
				return dp[len][cat]=dp[len-1][cat-1]*a[len];
		}
	}
}

int main()
{
	int n,k;
	ll max,sum=1;
	cin >> n >>k;
	for(int i=1;i<=n;i++)
		cin >> a[i];
	for(int i=1;i<=n;i++)	// 找出前i项中最大值 
	{
		max=a[i];
		for(int j=i+1;j<=i;j++)
			if(max<a[j]) max=a[j];
		dp[i][1]=max;
		b[i][1]=1;
	}
	
	for(int i=1;i<=n;i++)	//计算前i项的乘积 
	{
		sum*=a[i];
		dp[i][i]=sum;
		b[i][i]=1;
	}
	cout << mod_self(dp_func(n,k));
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值