题解:洛谷 P1249 最大乘积

【题目来源】

洛谷:P1249 最大乘积 - 洛谷 (luogu.com.cn)

【题目描述】

一个正整数一般可以分为几个互不相同的自然数的和,如 \(3=1+2\)\(4=1+3\)\(5=1+4=2+3\)\(6=1+5=2+4\)

现在你的任务是将指定的正整数 \(n\) 分解成若干个互不相同的自然数的和,且使这些自然数的乘积最大。

【输入】

只一个正整数 \(n\),(\(3\le n\le 10000\))。

【输出】

第一行是分解方案,相邻的数之间用一个空格分开,并且按由小到大的顺序。

第二行是最大的乘积。

【输入样例】

10

【输出样例】

2 3 5
30

【算法标签】

《洛谷 P1249 最大乘积》 #贪心# #高精度#

【代码详解】

#include<iostream>
#include<algorithm>
using namespace std;

const int L = 500; // 定义高精度计算的最大位数

// 高精度乘法函数:计算两个字符串表示的大整数的乘积
string mul(string a, string b)
{
    string s; // 存储结果
    int na[L], nb[L], nc[L]; // na, nb 存储两个乘数的每一位,nc 存储乘积的每一位
    int La = a.size(), Lb = b.size(); // La 和 Lb 分别是两个乘数的长度
    fill(na, na + L, 0); // 初始化 na 数组为 0
    fill(nb, nb + L, 0); // 初始化 nb 数组为 0
    fill(nc, nc + L, 0); // 初始化 nc 数组为 0

    // 将字符串 a 转换为整数数组 na(逆序存储)
    for (int i = La - 1; i >= 0; i--) na[La - i] = a[i] - '0';
    // 将字符串 b 转换为整数数组 nb(逆序存储)
    for (int i = Lb - 1; i >= 0; i--) nb[Lb - i] = b[i] - '0';

    // 高精度乘法核心计算
    for (int i = 1; i <= La; i++) 
        for (int j = 1; j <= Lb; j++) 
            nc[i + j - 1] += na[i] * nb[j]; // 逐位相乘并累加到结果数组

    // 处理进位
    for (int i = 1; i <= La + Lb; i++) 
	{
        nc[i + 1] += nc[i] / 10; // 进位
        nc[i] %= 10; // 取个位数
    }

    // 将结果数组转换为字符串
    if (nc[La + Lb]) s += nc[La + Lb] + '0'; // 如果最高位不为 0,添加到结果
    for (int i = La + Lb - 1; i >= 1; i--) 
        s += nc[i] + '0'; // 从高位到低位依次添加

    return s; // 返回结果字符串
}

// 将整数转换为字符串
string f(int a)
{
    char ch[10], t; // ch 用于存储字符形式的数字
    int i = 0;
    int j;
    // 将整数 a 转换为字符数组(逆序)
    while (a) 
	{
        ch[i] = a % 10 + '0'; // 取个位数并转换为字符
        a /= 10; // 去掉个位数
        i++;
    }
    ch[i] = '\0'; // 添加字符串结束符

    // 将字符数组倒序,得到正确的字符串
    for (i = i - 1, j = 0; j <= i / 2; j++, i--) 
	{
        t = ch[i];
        ch[i] = ch[j];
        ch[j] = t;
    }

    return ch; // 返回字符串
}

int n, a[1005]; // n 是输入的整数,a 数组存储拆分后的整数
string s[1005]; // s 数组存储拆分后的整数的字符串形式
int c = 1; // c 记录拆分后的整数个数

int main()
{
    string m = "1"; // m 用于存储乘积结果,初始值为 1

    // 输入
    cin >> n;

    // 特判:如果 n 小于等于 4,直接输出 n 和 n
    if (n <= 4) 
	{
        cout << n << endl << n;
        return 0;
    }

    // 拆项:将 n 拆分为若干个整数,使得这些整数的乘积最大
    for (int i = 2; i <= n; i++) 
	{
        if (n >= i) 
		{
            n -= i; // 从 n 中减去 i
            a[c++] = i; // 将 i 存入 a 数组
            s[c - 1] = f(i); // 将 i 转换为字符串并存入 s 数组
        } 
		else 
            break; // 如果 n 不足以减去 i,退出循环
    }

    // 如果有余数,从最高位开始加一
    for (int i = c - 1; i >= 1; i--) 
	{
        if (n > 0) 
		{
            a[i]++; // 当前位加一
            s[i] = f(a[i]); // 更新字符串形式
            n--; // 余数减一
        }
    }

    // 如果还有余数,让最后一个数加一
    if (n > 0) 
	{
        a[c - 1]++;
        s[c - 1] = f(a[c - 1]);
    }

    // 高精度乘法计算拆分后的整数的乘积
    for (int i = 1; i < c; i++) 
	{
        cout << a[i] << " "; // 输出拆分后的整数
        m = mul(s[i], m); // 计算乘积
    }

    // 输出结果
    cout << endl << m;
    return 0;
}

【运行结果】

10
2 3 5 
30
posted @ 2026-02-17 08:27  团爸讲算法  阅读(1)  评论(0)    收藏  举报