最大乘积
题目描述
小明开始研究起了数学,他发现一个正整数可以分为几个互不相同的自然数使得这些自然数的乘积最大,他想知道这个几个自然数各是多少,并且输出最大的乘积。现在他想请你帮他完成这个心愿。
输入
一行包含一个正整数
n
(
3
≤
n
≤
1
0
4
)
n(3\le n\le 10^4)
n(3≤n≤104)
输出
输出包含两行
第一行包含拆分后的若干个自然数,从小到大排序
第二行包含一个整数,表示最大乘积
样例输入
10
样例输出
2 3 5
30
AC代码
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 505;
int n;
vector<int> s, a(1, 1);
void mul(int b) {
int t = 0;
for(int i = 0; i < a.size(); i++) {
a[i] = a[i] * b + t;
t = a[i] /10;
a[i] %= 10;
}
while(t) {
a.push_back(t % 10);
t /= 10;
}
}
int main() {
scanf("%d", &n);
for(int i = 2; i <= n; i++) {
s.push_back(i);
n -= i;
}
for(int i = s.size()-1; n && i >= 0; i--, n--) {
s[i] += 1;
}
for(int x : s) {
printf("%d ", x);
mul(x);
}
printf("\n");
reverse(a.begin(), a.end());
for(int x : a) printf("%d", x);
return 0;
}
代码分析
如果将一个数分成若干个不重复的数,使得乘积最大,那么一定贪心分的越多越好(但如果能分成重复的数则不一定,比如6分成三个2最佳)
既然要分的最多,那么先分出一个2 ,再分出一个3 … 以此类推(不能从1开始分,因为1不会对答案做出贡献)。这种分法使得最后可能有余数存在。若是单纯的几个数相乘,那么把余数分到较小的数肯定比分到较大的数上得到的乘积更大,但是由于数不能重复,所以开始只能将余数中的一个1分到最大的数上,然后再将一个1分到第二大的数上(此时保证不会有重复的数),以此类推。
所以对于余数的操作是:从最大的数开始向前,依次分配1 ,全部数分配 1之后还有剩余,则继续从最大的数向前分配。比如13 先分成 2,3,4,余 4,每个数分一个 1之后变为3,4,5 ,仍然余 1,将1分给5变为3,4,6即可。
最后注意一下,相乘之后可能是个大数,所以每次乘法可以看做高精乘低精。可以先乘最后统一进位,复杂度上限为
O
(
500
n
)
O(500\sqrt n)
O(500n)