P1249 最大乘积
题目描述
一个正整数一般可以分为几个互不相同的自然数的和,如 3=1+2 4=1+3,5=1+4=2+3,6=1+5=2+4。
现在你的任务是将指定的正整数 n 分解成若干个互不相同的自然数的和,且使这些自然数的乘积最大。
输入格式
只一个正整数 n, (3 ≤ n ≤ 10000)。
输出格式
第一行是分解方案,相邻的数之间用一个空格分开,并且按由小到大的顺序。
第二行是最大的乘积。
输入输出样例
输入 #1 复制
10
输出 #1 复制
2 3 5
30
分析过程
题目需要分解一个自然数,使得分解之后的数字相乘得到的数字最大,输出该组数字,并且输出乘积结果。
首先最后输出乘积是高精度乘法,现在要获得分解一个数字乘积的最大值的组合。因为数字不能够重复,所以说分解的数字越多乘积则就最大,所以从2~n做一遍扫描,比如9分解出来的最大的组合应该为[2,3,4]。但是有可能会出现有余数的情况,例如需要分解n = 12,扫描得到结果[2,3,4]余3,3可以有很多种分配方法:
1 2 3 | 1. 一个个向前分配,得到结果[3,4,5] 乘积的结果为60。 2. 直接分配到最大的数字得到结果[2,3,7] 乘积结果为42。 3. 再向后分配一个数字得到[2,3,4,5]超出了2,再删除2,得到结果序列[3,4,5],可见于方案一一样。 |
从上述的几种策略可以看出,直接分配到最大的数字并不靠谱,方案1、3实际上是同一种方案,③是对①的简化。
需要注意的是,当例子是10的时候,得到序列[2,3,4]余1,在这里我们进行③的操作得到,[2,3,4,5]超出4删除4得到[2,3,5]。
然后当例子n为8时,我们得到[2,3]余3,进行③操作得到,[2,3,4]超出1,本来应该是删除1,但是序列中并没有1,我们选择先删去2,然后最后一个数字加上1得到序列[3,5]。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | #include<bits/stdc++.h> using namespace std; string mul(string sa, int b) { string res; vector<int> a, c; for (size_t i = sa.size() - 1; ~i; i--) a.push_back(sa[i] - '0'); int t = 0; for (int i = 0; i < a.size(); i++) { t += a[i] * b; c.push_back(t % 10); t /= 10; } while (t) { c.push_back(t % 10); t /= 10; } for (int i = c.size() - 1; ~i; i--) res += c[i] + '0'; return res; } int d[10010]; void process(int n) { int s = 0; for (int i = 2; i <= n; i++) { s += i; d[i] = true; if (s > n) { if (s - n == 1) { d[2] = false; d[i] = false; d[i + 1] = true; break; } d[s - n] = false; break; } } } string solve() { string s = "1"; for (int i = 0; i < 10010; i++) { if (d[i]) { s = mul(s, i); } } return s; } int main() { ios::sync_with_stdio(false); //freopen("in.txt", "r", stdin); int n; cin >> n; process(n); for (int i = 0; i < 10010; i++) { if (d[i]) cout << i << " "; } cout << endl; cout << solve() << endl; return 0; } |
值得关注的地方在于
如果把题目中间的数字不重复的条件删去,那么就会有几个新的思路。
我在查资料的过程中,找到一个和我思路一样的流程,放在此时
- a 不能分成1 与 a-1 的和。
- a <= 4 时,分解后的积 <= a, 当且仅当 4 = 2 +2 时相等。
- a分为两个数之和,并且这两个数的乘积最大. x= a/2, y = a-x, 继续分x, y。递归。
另一边,把n分解成几个自然数的和,并且使得乘积最大有以下结论。
关键是明白:把一个自然数N拆分成若干个自然数的和,只有当这些分拆数由2或3组成,其中2最多为2个时,这些分拆数的乘积最大。
简而言之,就拆3就拆3,三个2可以变成两个3,因为2 + 2 + 2 等于 3 + 3,且 3 * 3 > 2 * 2 * 2。
有人证明结果最好的分割是自然对数e,3是离自然对数最近的一个自然数。