问题 G: 【贪心】最大乘积
时间限制: 1 Sec 内存限制: 128 MB
题目描述
一个正整数一般可以分为几个互不相同的自然数的和,如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
【思路】
1.若n=3 or n=4,好办,特判;
2.对于比5大(含)的n,本着最终分解的数字的乘积最大而又不重复的原则,显然可以将n分成2,3,4,...n-sum_of_front. 现在要考虑的是,要在分解到多少的时候停下来。很明显,按照顺序,最后的分解不下去的结束条件是剩余的可分解的数目不大于已经分出来的组数。若分解到最后恰好完毕,则结束,反之,还要把剩余的n’们填补上去。本着不重复且积最大的原则,从后往前进行。注意n与边界的大小。最后,注意乘积比较大,ans高精度处理一下。
【代码】
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
using namespace std;
const int mx=10000;
int n,i,j,l,t,d[mx+10],ans[mx+10];
int main()
{
while (~scanf("%d",&n)&&n)
{
if (n==3) {
printf("1 2\n2\n");
continue;
}
else if (n==4){
printf("1 3\n3\n");
continue;
}
l=1;
while (n>l){//n>=5,d[1]=2,d[2]=3,...
d[l]=l+1;
l++;
n-=l;
}
l--;
t=l;
while (n){//n>0,haven't finished yet.from tail to head inc...
d[t]++;
n--;
t--;
if (!t) t=l;
}
for (i=1;i<l;++i) printf("%d ",d[i]);
printf("%d\n",d[l]);
memset(ans,0,sizeof(ans));//GJD!
t=0;
ans[t]=1;
for (i=1;i<=l;++i){
for (j=0;j<=t;++j){
ans[j]*=d[i];
}
t+=5;
for (j=0;j<t;++j){
ans[j+1]+=ans[j]/10;
ans[j]=ans[j]%10;
}
while (!ans[t]) t--;
}
for (i=t;i>=0;--i) printf("%d",ans[i]);
printf("\n");
}
return 0;
}