题目
一个正整数一般可以分为几个互不相同的自然数的和,如3=1+2,4=1+3,5=1+4=2+3,6=1+5=2+4。
现在你的任务是将指定的正整数n分解成若干个互不相同的自然数的和,且使这些自然数的乘积最大。
输入输出格式
输入格式
只一个正整数n(3≤n≤10000)。
输出格式
第一行是分解方案,相邻的数之间用一个空格分开,并且按由小到大的顺序。
第二行是最大的乘积。
解析
本题要先用简单的数论和贪心找到最优解的组成方法,再用高精度乘法求积。
以2004为例,由于把2004分拆成若干个互不相等的自然数的和的分法只有有限种,因而一定存在一种分法,使得这些自然数的乘积最大。
若1作因数,则显然乘积不会最大。把2004分拆成若干个互不相等的自然数的和,因数个数越多,乘积越大。为了使因数个数尽可能地多,我们把2004分成2+3…+n直到和大于等于2004。
若和比2004大1,则因数个数至少减少1个,为了使乘积最大,应去掉最小的2,并将最后一个数(最大)加上1。
若和比2004大k(k≠1),则去掉等于k的那个数,便可使乘积最大。
-
例如15:s=2+3+4+5+6刚好大于15,s-15=5,所以把5去掉。
-
又例如13:s=2+3+4+5刚好大于13,s-13=1,所以去掉2,并把5加1,即3 4 6
代码1
#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<<1<<' '<<2<<endl;
cout<<2<<endl;
return 0;
}
if(n==4){
cout<<1<<' '<<3<<endl;
cout<<3<<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){//正好大1,减去2,最后一个数字加1
a[tot]++;
a[0]=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;
}
代码2
高精度求积的方式可以改变一下
#include<iostream>
using namespace std;
int n,s[10001],a[10001],len=1;
void mul(int x){
int w=0;//w为余数
for(int i=1;i<=len;i++){
s[i]=s[i]*x+w;
w=s[i]/10;
s[i]%=10;
}
while(w>0){
s[len+1]+=w%10;
len++;
w/=10;
}
}
int main(){
cin>>n;
if(n==3){
cout<<1<<' '<<2<<endl;
cout<<2<<endl;
return 0;
}
if(n==4){
cout<<1<<' '<<3<<endl;
cout<<3<<endl;
return 0;
}
s[0]=s[1]=1;
int tot=0,Sum=0;
for(int i=2;Sum<n;Sum+=i,i++){
a[++tot]=i;
}
if(Sum>n+1){
a[Sum-n-1]=0;
}
if(Sum==n+1){
a[tot]++;
a[1]=0;
}
for(int i=1;i<=tot;i++){
if(a[i]!=0){
cout<<a[i]<<' ';
mul(a[i]);
}
}
cout<<endl;
for(int i=len;i>=1;i--){
cout<<s[i];
}
return 0;
}