1157. 【贪心算法】最大乘积

题目描述

一个正整数一般可以分为几个互不相同的自然数的和,如3=1+2,4=1+3,5=1+4=2+3,6=1+5=2+4,…。现在你的任务是将指定的正整数n分解成若干个互不相同的自然数的和,且使这些自然数的乘积最大。

输入

只一个正整数n,(3≤n≤10000)。

输出

第一行是分解方案,相邻的数之间用一个空格分开,并且按由小到大的顺序。
第二行是最大的乘积。

样例输入 
10
样例输出 
2 3 5
30

题目简述

让你将一个正整数 n 分解成若干个自然数之和,要求这些数的乘积最大。

做题步骤

  1. 观察性质;
  2. 得出结论;
  3. 完善代码。
观察性质

先举出几个简单的例子:

  • 5→2×35→2×3
  • 6→2×46→2×4
  • 9→2×3×49→2×3×4
  • 10→2×3×510→2×3×5

我们观察到,大部分分解出来的数都是较为连续的。

得出结论

考虑这样一种贪心策略:

首先构造出连续一段自然数,使得和恰好大于或等于 �n ,然后找到一个合适的数并更改(如果等于 �n 就不更改),使得和满足要求。

例如分解一个数 1515 :

  • 首先找到连续一段自然数: 2+3+4+5+6>152+3+4+5+6>15 (为什么要从 22 开始而不是 33 或更大?请思考);
  • 发现 2+3+4+5+6=202+3+4+5+6=20 ,恰好与 1515 相差 55 ;
  • 把 55 删掉,得到 2+3+4+6=152+3+4+6=15 ,计算答案。

若找到的和与 �n 相差 11 ,可以直接删除 22 并将最后一个数加上 11 。

注意:当 �=3,4n=3,4 时并不符合上述的贪心策略,需要特判。

code:
#include<iostream>
using namespace std;
int a[10001]={};
int s[10001]={};
int n,len=1;
void mul(int x)
{
	for(int i=1;i<=len;i++)s[i]*=x;
	for(int i=1;i<=len;i++)
	{
		s[i+1]+=s[i]/10;
		s[i]%=10;
	}
	while(s[len+1]>0)
	{
		len++;
		s[len+1]+=s[len]/10;
		s[len]%=10;
	}
}
int main()
{
	cin>>n;
	if(n==3)
	{
		cout<<3<<endl;
		cout<<3<<endl;
		return 0;
	}
	if(n==4)
	{
		cout<<4<<endl;
		cout<<4<<endl;
		return 0;
	}
	s[0]=s[1]=1;
	int Sum=0,tot=0;
	for(int i=2;Sum<n;Sum+=i,i++)a[++tot]=i;
	if(Sum>n+1)a[Sum-n-1]=0;
	else if(Sum==n+1)a[tot]++,a[1]=0;
	for(int i=1;i<=tot;i++)
	{
		if(a[i])
		{
			cout<<a[i]<<' ';
			mul(a[i]);
		}
	}
	cout<<endl;
	for(int i=len;i>=1;i--)
		cout<<s[i];
	cout<<endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值