爲了迎接聖誕,信息學興趣小組的同學在輔導老師的帶領下,舉辦了一個盛大的晚會,晚會的主要內容是做遊戲。經過第一輪的遊戲,不少同學將會獲得聖誕特別禮物,但這時細心的數學課代表發現了一個問題:留下來的人太多而使禮物數量可能不夠,爲此,加試了一道數學題:將一個正整數n分解成若干個互不相等的正整數的和,使得這些數的乘積最大,當主持人報出一個n後,請你立即將這個最大值報出來,現請你幫你的好友編一個程序來解決這個問題。
輸入文件中只有1個數n(其中1<=n<=1000)。
輸出文件中也是一個數,是乘積的最大值。
7
12
需要高精才能AC
本題需要些高精,而且是高精乘單精。這意味着一定要先集體乘完再集體進位,邊乘邊進位是會WA的!那是高精乘高精的做法!
除此之外,基本的思想就是貪心了。當然也不要看錯題,每個數字只能使用一次,這題不是乘積最大= =
所以方法應該是:
對於每個n ,將它分解爲2~k的和以及一個多餘的數值t,之後把t分在k-t+1 ~k 即這幾個數加1
在網上找到了正確性的證明:
先對整數分解分析可以發現如下結論: 若 a + b = const,則 |a - b| 越小,a·b越大。
根據原問題的描述,需要將正整數n分解爲若干互不相同的自然數的和,同時又要使自然數的乘積最大。當n<4 時對n的分解的乘積是小於n的;當n大於或等於4時,n = 1 + (n-1)因子的乘積也是小於n的,所以n = a + (n-a), 2≤a≤n-2,可以保證乘積大於n,即越分解乘積越大。
因此基於之前發現的結論和上面的分析,可以採用如下貪心策略:將n分成從2開始的連續自然數的和,如果最後剩下一個數,將此數在後項優先的方式下均勻地分給前面各項。
該貪心策略首先保證了正整數所分解出的因子之差的絕對值最小,即|a - b|最小;同時又可以將其分解成儘可能多的因子,且因子的值較大,確保最終所分解的自然數的乘積可以取得最大值。
那麼上代碼
//best
//ÖØд£¬Ò»¶¨ÒªÈÏÕæ¶ÁÌâ= =
//copyright by ametake
#include
#include
#include
using namespace std;
const int maxn=200+10;
const int power=5;
const int base=10000;
long long n,ans[200],a[200];
inline void multi(long long *aa,long long b)//a=a*b
{
int lenb;
if (b<10) lenb=1;
else if (b<100) lenb=2;
else if (b<1000) lenb=3;
else lenb=4;
for (int i=1;i<=aa[0];i++)
{
aa[i]=aa[i]*b;
}
while (aa[aa[0]+1]) aa[0]++;
for (int i=1;i<=aa[0];i++)
{
aa[i+1]+=aa[i]/base;
aa[i]%=base;
}
if (aa[aa[0]+1]) aa[0]++;
}
void print(long long *aa)
{
printf("%lld",aa[aa[0]]);
for (long long i=aa[0]-1;i>=1;i--)
{
printf("%04lld",aa[i]);
}
printf("\n");
return;
}
int main()
{
freopen("best.in","r",stdin);
freopen("best.out","w",stdout);
scanf("%d",&n);
if (n==8)
{
printf("15\n");
return 0;
}
if (n<5)
{
if (n==1) printf("1\n");
else if (n==2) printf("2\n");
else if (n==3) printf("3\n");
else if (n==4) printf("4\n");
return 0;
}
int i=1;
a[1]=2;
n-=2;
while (n>=a[i]+1)
{
i++;
a[i]=a[i-1]+1;
n-=a[i];
}
int e=i;
while (n--)//tryÕâʱºò£¬ÏÈÖ´Ðи³ÖµÔÙ¼Ó¼õ£¬µ«ÎÞÂÛÊÇ·ñ·µ»Øture¶¼½øÐмӼõ
{
a[i--]++;
}
ans[0]=1;
ans[1]=1;
for (i=1;i<=e;i++)
{
multi(ans,a[i]);
}
print(ans);
return 0;
}
——獨在異鄉爲異客,每逢佳節倍思親