题目描述
一个正整数一般可以分为几个互不相同的自然数的和,如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 分解成若干个自然数之和,要求这些数的乘积最大。
做题步骤
- 观察性质;
- 得出结论;
- 完善代码。
观察性质
先举出几个简单的例子:
- 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;
}