纪中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 具体限制
题目描述
一个正整数一般可以分为几个互不相同的自然数的和,如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)。
输出格式
第一行是分解方案,相邻的数之间用一个空格分开,并且按由小到大的顺序。
第二行是最大的乘积。
输入输出样例
10
2 3 5 30
Solution
考试前,很久、很久、很久之前,我在嵊州与同学一起刷题。随机跳到了这道题,但是都不会。
于是,愉快的放弃了……
于是,今天,我死了。
Algorithm1
尝试用dfs暴力的算。
(对后面的找规律十分重要)
Code1
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
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
这道题的数据范围也比较小,所以就不需要做那些省时间的高精度操作了