纪中23日c组T2 2159. 【2017.7.11普及】max 洛谷P1249 最大乘积

纪中2159. max 洛谷P1249 最大乘积

说明:这两题基本完全相同,故放在一起写题解

纪中2159. max

(File IO): input:max.in output:max.out

时间限制: 1000 ms  空间限制: 262144 KB  具体限制  

Goto ProblemSet

题目描述

 一个正整数一般可以分为几个互不相同的自然数的和,如3=1+2,4=1+3,5=1+4=2+3,6=1+5=2+4,…。
现在你的任务是将指定的正整数n分解成m个(m>=1)互不相同的自然数的和,且使这些自然数的乘积最大。

输入

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

输出

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

样例输入

10

样例输出

2 3 5
30

数据范围限制

30%的数据  3<=n<=100

洛谷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

Solution

考试前,很久、很久、很久之前,我在嵊州与同学一起刷题。随机跳到了这道题,但是都不会。

于是,愉快的放弃了……

于是,今天,我死了。

Algorithm1

尝试用dfs暴力的算。

(对后面的找规律十分重要)

Code1

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<map>
 7 #include<set>
 8 #include<queue>
 9 #include<vector>
10 #define IL inline
11 #define re register
12 using namespace std;
13 
14 IL int read()
15 {
16     re int res=0;
17     re char ch=getchar();
18     while(ch<'0'||ch>'9')
19         ch=getchar();
20     while(ch>='0'&&ch<='9')
21         res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
22     return res;
23 }
24 int n,maxans;
25 bool use[10001];
26 int q[10001];
27 int tail;
28 int ans[10001];
29 int maxlen;
30 IL void dfs(int depth,int sum,int times)
31 {
32     if(sum==n){
33         if(maxans<times){
34             memset(ans,0,sizeof(ans)); 
35             for(int i=0;i<tail;i++) ans[i]=q[i];
36             maxlen=tail;
37             maxans=times;
38         } 
39         return;
40     }
41     if(sum>n) return;
42     for(int i=2;i+sum<=n;i++)
43     {
44         if(!use[i]){
45             q[tail++]=i;
46             use[i]=1;
47             dfs(depth+1,sum+i,times*i);
48             q[--tail]=0;
49             use[i]=0;
50         }
51     }
52 }
53 int main()
54 {
55 //    freopen("max.in","r",stdin);
56 //    freopen("max.out","w",stdout);
57     n=read();
58     dfs(0,0,1);
59     for(int i=0;i<maxlen;i++) cout<<ans[i]<<" ";
60     cout<<endl<<maxans;
61     return 0;
62 }
Code1
n=2
2 
2

n=3
3 
3

n=4
4 
4

n=5
2 3 
6

n=6
2 4 
8

n=7
3 4 
12

n=8
3 5 
15

n=9
2 3 4 
24

n=10
2 3 5 
30

n=11
2 4 5 
40

n=12
3 4 5 
60

n=13
3 4 6 
72

n=14
2 3 4 5 
120

n=15
2 3 4 6 
144

n=16
2 3 5 6 
180

n=17
2 4 5 6 
240

n=18
3 4 5 6 
360

n=19
3 4 5 7 
420

n=20
2 3 4 5 6 
720

n=21
2 3 4 5 7 
840

n=22
2 3 4 6 7 
1008

n=23
2 3 5 6 7 
1260

n=24
2 4 5 6 7 
1680

n=25
3 4 5 6 7 
2520

n=26
3 4 5 6 8 
2880

n=27
2 3 4 5 6 7 
5040

n=28
2 3 4 5 6 8 
5760

n=29
2 3 4 5 7 8 
6720

n=30
2 3 4 6 7 8 
8064

n=31
2 3 5 6 7 8 
10080

n=32
2 4 5 6 7 8 
13440

n=33
3 4 5 6 7 8 
20160

n=34
3 4 5 6 7 9 
22680

n=35
2 3 4 5 6 7 8 
40320

n=36
2 3 4 5 6 7 9 
45360

n=37
2 3 4 5 6 8 9 
51840

n=38
2 3 4 5 7 8 9 
60480

n=39
2 3 4 6 7 8 9 
72576

n=40
2 3 5 6 7 8 9 
90720
table

Algorithm2

尝试找规律

首先,1肯定是不能取的(1本身除外)(这不是废话吗?占总和又不算乘积的说……)

有一些特别的数,比如5,

它与比它小的数字不一样:

5被分成了2,3

但是比5小的数只被分成了一个数

像这样的数,还有很多,比如:

9:2,3,4

14:2,3,4,5

20:2,3,4,5,6

………………

于是我们就可以猜着说:

如果一个数可以被分成从2开始的连续的一串数字之和

那么这些数字就是这个数的“最大乘积”。

要是不能分成这样子呢?

还是先把它分成这样子,看看剩下来的数字吧

例如:

5被分成2,3

6不能正好分成从2开始连续的数字串

但是它被分成了2,3+1

7则被分成了2+1,3+1

8则被分成了2+1,3+2

9可以正好分成从2开始连续的数字串

……………………

那不就先减,减到不能减,再将2,3,4,5,6……这个数字串从右到左,再从右到左反复+1嘛!

(+1的过程也可以用除法和余数实现)

最后求乘积可是要用高精度的呦!

Code2

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<map>
 7 #include<set>
 8 #include<queue>
 9 #include<vector>
10 #define IL inline
11 #define re register
12 using namespace std;
13 int n;
14 int arr[10000];
15 int a[10000];
16 int main()
17 {
18 //    freopen("max.in","r",stdin);
19 //    freopen("max.out","w",stdout);
20     cin>>n;
21     int i=2;
22     while(n-i>=0) n-=i++;i--;
23     for(int j=2;j<=i;j++)
24         arr[j]=j;
25     if(n)//现在有i-1个数 
26     {
27         int j;
28         for(j=2;j<=i;j++) arr[j]+=n/(i-1);
29         for(j=i;j>=i+1-n%(i-1);j--) arr[j]++;
30     }
31     for(int j=2;j<=i;j++) cout<<arr[j]<<" ";
32     a[0]=1;
33     for(int j=2;j<=i;j++)
34     {
35         for(int k=0;k<10000;k++)
36         {
37             a[k]*=arr[j];
38         }
39         for(int k=0;k<10000;k++)
40         {
41             a[k+1]+=a[k]/10;
42             a[k]%=10;
43         }
44     }
45     cout<<endl;
46     bool flag=0;
47     for(int j=9999;j>=0;j--)
48     {
49         if(a[j]) flag=1;
50         if(flag) cout<<a[j];
51     }
52     return 0;
53 }

Attention

这道题的数据范围也比较小,所以就不需要做那些省时间的高精度操作了

posted @ 2019-08-23 16:17  Vanilla_chan  阅读(361)  评论(0编辑  收藏  举报