1.思路
思路可能不完全正确,本人萌新,大佬轻喷。
(1).首先找到贪心策略
基本结论:
我们把n分解成从2开始的连续的自然数之和,如果最后有剩余的数res,将res从大数开始向前依次分配1,重复执行直到res为0。比如n为13时,我们得到2、3、4、4,此时res为4,分别给4、3、2分配1,我们得到3、4、5、1,此时res为1,给5分配1,我们得到3、4、6,结果就是3*4*6=72。
证明:
首先我们易知n分拆成若干个大于1的互不相等的自然数的和,自然数的个数越多,乘积越大。
从 2 开始的连续自然数之和分解的优势: 从 2 开始的连续自然数之和分解的优势在于,这样可以确保使用尽可能多的连续自然数,并且保持它们的间隔较小,以增加因数的个数。之所以不从1开始分解,是因为将n分成1和另外一些数时它们的乘积会失去一个数值的贡献,比如6可以分成1、2、3,得到的结果为2*3=6,和把5分成2、3得到的结果一样,不如把6分成2、4。
将剩余的数优先平均分给前面的各项的优势:将res从大数开始向前依次分配,可以使得到的自然数在个数一定的情况下增加数值,从而增大乘积。之所以不从小数开始向后分配是因为,res的值不等于前面自然数的个数时从小数开始向后分配会导致得到的自然数出现重复,比如从13得到2、3、4、4后,把res从前往后分配我们将得到4、4、5,不符合题意。
(2).用高精度计算结果
考虑到使用c/c++书写代码时,如果n较大,我们分解得到的自然数个数就会比较多,相乘会超过long long甚至__int128的数据范围,所以需要写一个高精度乘法。
2.代码
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define Fi first
#define Se second
#define yes cout<<"YES\n"
#define no cout<<"NO\n"
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> Pii;
#pragma GCC optimize(2)
vector<int> mul(vector<int> &ans,int b){
vector<int> C;
int t=0,len=ans.size();
for(int i=0;i<len;i++){
t+=ans[i]*b;
C.push_back(t%10);
t/=10;
}
while(t){
C.push_back(t%10);
t/=10;
}
while(C.size()>1&&C.back()==0) C.pop_back();
return C;
}
int main()
{
int n,sum=0;
cin>>n;
if(n==1){
cout<<1<<endl<<1<<endl;
return 0;
}
vector<int> g;
for(int i=2;i<=n;i++){
sum+=i;
g.push_back(i);
if(sum>=n) break;
}
if(sum==n+1){
g.erase(g.begin());
int tem=*g.rbegin()+1;
g.erase(g.end()-1);
g.push_back(tem);
}
else if(sum>n){
int tem=sum-n;
auto it=lower_bound(g.begin(),g.end(),tem);
g.erase(it);
}
// for(auto i:g) cout<<i<<endl;
vector<int> ans;
ans.push_back(1);
for(auto i:g){
ans=mul(ans,i);
cout<<i<<' ';
}
cout<<endl;
reverse(ans.begin(),ans.end());
for(auto i:ans) cout<<i;
cout<<endl;
return 0;
}
/*
*
* ┏┓ ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃ ┃
* ┃ ━ ┃ ++ + + +
* ████━████+
* ◥██◤ ◥██◤ +
* ┃ ┻ ┃
* ┃ ┃ + +
* ┗━┓ ┏━┛
* ┃ ┃ + + + +Code is far away from
* ┃ ┃ + bug with the animal protecting
* ┃ ┗━━━┓ 神兽保佑,代码无bug
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛ + + + +
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛+ + + +
*/