洛谷P1249最大乘积

洛谷 p1249 最大乘积

题目大意


将N分解成若干个互不相同数字之和,求乘积的最大值。

思路


利用 lna + lnb = ln(a + b),将乘积的最大值转换为和的最大值。题目就可以化解为,从1, 2, 3…n中选出一些数是他们的和最大。

相当于是一个01背包问题和一个高精度乘法。

题目描述

一个正整数一般可以分为几个互不相同的自然数的和,如 3=1+23=1+2,4=1+34=1+3,5=1+4=2+35=1+4=2+3,6=1+5=2+46=1+5=2+4。

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

输入格式

只一个正整数 nn,(3 \leq n \leq 100003≤n≤10000)。

输出格式

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

第二行是最大的乘积。

输入输出样例

输入 #1

1
10

输出 #1

1
2
2 3 5
30

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
68
69
70
71
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;

struct bigN
{
int d[10000] = {0};
int len = 0;
};

bigN multi(bigN a, int b);
void printN(bigN a);
vector<int> ans;

int main(int argc, const char *argv[])
{
int N;
cin >> N;
double W[N + 1], DP[N + 1];
int flag[N + 1];
for(int i = 1; i <= N; i++) {
W[i] = log(i);
DP[i] = 0;
flag[i] = 0;
}
for(int i = 1; i <= N; i++)
for(int j = N; j >= i; j--)
if(DP[j - i] + W[i] > DP[j])
{
DP[j] = DP[j - i] + W[i];
flag[j] = j - i;
}
for(int i = N; i; i = flag[i])
ans.push_back(i - flag[i]);
bigN a;
a.len = 1; a.d[0] = 1;
for(int i = ans.size() - 1; i >= 0; i--)
{
cout << ans[i] << (i == 0 ? "\n" : " ");
a = multi(a, ans[i]);
}
printN(a);

return 0;
}


bigN multi(bigN a, int b)
{
bigN c;
int carry = 0;
for(int i = 0; i < a.len; i++)
{
int temp = a.d[i] * b + carry;
c.d[c.len++] = temp % 10;
carry = temp / 10;
}
while(carry)
{
c.d[c.len++] = carry % 10;
carry /= 10;
}
return c;
}

void printN(bigN a)
{
for(int i = a.len - 1; i >= 0; i--)
cout << a.d[i];
}
作者

Jhuoer Yen

发布于

2021-03-24

更新于

2023-09-18

许可协议

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×