洛谷题单指南-模拟和高精度-P1249 最大乘积
原题链接:https://www.luogu.com.cn/problem/P1249
题意解读:
题目分两步,第一步是将整数拆分成不同自然数的和,第二步通过高精度计算这些因数的乘积,要使乘积最大,需要某种贪心思想。
解题思路:
如何保证整数拆分后因子的乘积最大呢,有几个原则:
1、最好不要包括因子1,但3、4除外,需要进行特殊处理
2、从2开始,连续拆分整数,依次拆分出2、3、4......直到和大于给定整数n
3、这时之前已经拆分出的数为a1、a2......ax,a1+a2+...+ax <= n
4、这时还剩余 r = n - (a1+a2+...+ax) 未分配
5、可以证明,将r平均的分配给a1、a2......ax,会使得乘积最大,因此依次给各个数加1,r减1,直到r为0
6、由于a1、a2......ax是递增的,不能从头开始分,可能会导致重复,因此从后开始分,可以使结果最大
举例:
n = 8,依次拆分2、3,
到4时2+3+4>8,4不能分,
剩余8 -(2+3)= 3,
给3加1得4,给2加1得3,现在拆分得到3、4,
还剩1,分给4,得到3、5。
如何存储拆分出来的因子,还能保证顺序呢?借助于桶数组可以很容易解决。
因子拆分出来之后,再进行高精度*低精度计算乘积即可。
分析完毕。
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 10005;
int n;
int nums[N]; // nums[i] = 1表示i是n的一个因子
int idx; //最大的因子
vector<int> mul(vector<int> &a, int b)
{
vector<int> result;
int t = 0;
for(int i = 0; i < a.size(); i++)
{
t += a[i] * b;
result.push_back(t % 10);
t /= 10;
}
while(t)
{
result.push_back(t % 10);
t /= 10;
}
return result;
}
int main()
{
cin >> n;
if(n == 3 || n == 4)
{
cout << 1 << " " << n - 1 << endl;
cout << 1 * (n - 1);
return 0;
}
int sum = 0;
for(int i = 2; i < n; i++)
{
if(sum + i > n) //如果sum + i超过n
{
int r = n - sum; //计算超出的部分,可以分给其他的因子
while(r) //分配原则是由大到小,每个因子分1,重复进行,直到分完,可以保证乘积最大
{
for(int j = idx; j >= 2; j--)
{
if(nums[j] && r)
{
nums[j] = 0, nums[j + 1] = 1; //给i加1的操作
if(j == idx) idx++;
r--;
}
else break;
}
}
break;
}
sum += i;
nums[i] = 1;
idx = i;
}
vector<int> res;
res.push_back(idx);
for(int i = 2; i < idx; i++)
{
if(nums[i]) res = mul(res, i);
}
for(int i = 0; i <= idx; i++)
if(nums[i]) cout << i << " ";
cout << endl;
for(int i = res.size() - 1; i >= 0; i--)
cout << res[i];
return 0;
}