正整數分解使得乘積最大問題
阿新 • • 發佈:2019-01-01
一、問題描述
設 n 是一個正整數。現在要求將 n 分解為若干個自然數之和,使得自然數的成績最大。輸出這個最大的乘積。
要求:
(1)要求這些自然數 互不相同。
(2)要求這些自然數 可以相同。(同一個數結果大於等於(1)的結果)
二、問題分析
1、要求這些自然數 互不相同:
先來看幾個數找找規律:
(1)小於等於 4 的情況就不用說了。
(2)從 5 開始寫起:5=2+3,6=2+4,7=3+4,8=3+5,9=2+3+4,10=2+3+5,11=2+4+5
Ps:從 1 開始寫沒意義,因為相乘還是 1*x==x 還少了相對於原來的 n 還少了 1 呢,更小了,所以從 2 開始才行~
發現規律如下:
- 儘量使得元素是連續的,(一律從 2 開始)。
- 如果連續加的時候,某個數 k 加的時候正好超出了 n ,則該數 k 不能算入,而是把讓 rest =(n - 前面 ( k - 1 ) 項總和),從後往前(因為一開始就使升序,所以也從大到小)均勻分配(+1)到各個元素,直到 rest == 0。
Code:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<vector> #include<stack> #include<bitset> #include<cstdlib> #include<cmath> #include<set> #include<list> #include<deque> #include<map> #include<queue> #define mem(a,b) memset(a,b,sizeof a); #define INF 0x3f3f3f3f using namespace std; typedef long long ll; int a[100],b[100]; int main() { int rs=0,len=0; for(int i=2;rs<=1100;i++) { a[len++]=i; rs+=i; } int n; while(~scanf("%d",&n)) { if(n<=4) // 沒辦法拆分成不同的數使乘積大於等於 (1*n) { //... continue; } rs=0; int k=0; for(int i=0;i<len-1;i++) { rs+=a[i]; if(n-rs<a[i+1]) { b[k++]=a[i]; rs=n-rs; int j=k-1; while(1) { b[j--]+=1; rs--; if(rs<=0) break; if(j==-1) j=k-1; } break; } else if(n-rs==a[i+1]) { b[k++]=a[i]; b[k++]=a[i+1]; break; } else b[k++]=a[i]; if(rs<=0) break; } printf("%d",b[0]); for(int i=1;i<k;i++) printf(" %d",b[i]); puts(""); } return 0; }
2、要求這些自然數 可以相同:
先來看幾個數找找規律:4=2+2,5=2+3,6=3+3,7=3+2+2,8=3+3+2,9=3+3+3
發現規律如下:
(1)元素不會超過4,因為4=2+2,又可以轉化為2的問題,而5=2+3,5<2*3,所以5總能分解成2和3。
(2)儘可能多分解出3,然後分解出2,不要分出1。
考慮任意一個數,除以3之後的結果有以下3種:
(1)能被3除斷(即整除),那麼就分解為3+3+...+3的情況即可。例如:9=3+3+3。
(2)被3除餘1,分解為3+3+...+3+2+2或者3+3+...+3+4的情況,例如:10=3+3+2+2
(3)被3除餘2,分解為3+3+...+3+2的情況,例如:11=3+3+3+2。
Code(注意:有秒殺公式):
#include<bits/stdc++.h>
#include<cmath>
#define mem(a,b) memset(a,b,sizeof a);
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int main()
{
int T; scanf("%d",&T);
int n;
while(T-- && ~scanf("%d",&n))
{
int rs;
if(n==0) rs=1; // 根據題目需要
else if(n<4) rs=n; // 根據題目需要
else
{
int cnt3,cnt2; // 3的個數 2的個數
if(n%2==1) // 奇數時
{
cnt3=(n-3)/6*2+1;
cnt2=(n-3)%6/2;
}
else // 偶數時
{
cnt3=n/6;
cnt2=n%6/2;
}
rs=pow(3,cnt3) * pow(2,cnt2);
}
printf("%d\n",rs);
}
return 0;
}