1. 程式人生 > >【原創】【HZOI】天明 (數學貪心)

【原創】【HZOI】天明 (數學貪心)

天明

題目描述

話說,自從天明那次看到高月駕駛機關獸後,心裡十分癢癢,於是找到高月,要她教自己駕駛機關獸。
高月:“我可是學了一年吶!”
而且,說實話,高月覺得以天明的智商,機關術可能有點……
於是乎,天明決定向月兒證明,自己的智商沒有問題!

天明四處打聽,終於打聽到了一種測智商的方法:將一個給定的數分成若干個互不相等的數的和,使得分成的數的乘積最大,分成的數的乘積代入到一個正相關的函
數中所得的值就是自己的智商。
所以,你需要幫助天明,讓他可以為自己開出一張“高智商”證明。(就是作弊
啦……)

輸入

僅一行,一個整數 n,就是你要分解的那個數。(其中1 ≤ n ≤ 1000)

輸出

一個整數,就是 n 分解成若干個互不相等的數的最大乘積。

樣例輸入

7

樣例輸出

12

分析

說在前面

為什麼同一道題寫兩篇部落格?
而且同一天發?
程式碼還一模一樣?

餘不知也。

分析

通過膜法/玄學/直覺/知識積累/打表/數學太好直接推/找呀找呀找規律,我們可以得出結論,在“互不相等”的前提下,拆的項越多,積越大

在這個前提下,對於給定數n:
把n拆成n=(2+3+4+5+6+…+t)+k的形式;(2~t是等差數列,但是n多數情況無法恰好拆成等差數列的形式,一般還剩一個小尾巴。。。。如果不剩?就很偷稅的直接23456*…*t了啊!)

k一定與2~t中的某一個數重複了,所以現在我們要進行的操作就是把k用膜法融入2~t中,以得到一個不重複的加數數列。

從k=1開始分析吧,我們能想到的就是把這個1加到t上面去,這樣就得到了n=1+2+3+…+(t-2)+(t-1)+(t+1);否則無論把1丟到2~t-1

中,都會產生重複。

k=2的時候,就有兩種選擇了,其一是讓t+=2,其二是t++,(t-1)++。(應該懂得起吧,就是指讓第t個加數從t變為t+2,後者類似)
這兩種哪種更優呢?

第一種方法的乘積為ans1=(t-1)!*(t+2)
第二種方法的乘積為ans2=(t-2)!*t*(t+1)
ans1/ans2=(t-1)*(t+2)/[t*(t+1)]<1(親自算一算,定能解百愁)
∴ans2>ans1
第二種方法更優。

對於更大的k,應該有類似的結論,就可以得出我前一篇blog所得出的結論:

記數列A是滿足A[i]=2+3+…+i的數列,則:
①若n=A[t],則ans=t!即23

4*…t;
②若n∈[A[t]+1,A[t+1]-2],將t!後面的n-A[t]項都加上1,再乘起來。(這個情況可以包含①)
③若n=A[t+1]-1,將2到t的每個數都加上1後,最後一項再加上一,即ans=3
45…*(t-1)t(t+2)

程式碼

#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int MAXN=1000+20;
int x,cnt,weis,help[MAXN],tosum[MAXN];
long long arr[MAXN];

int main()
{
	for(int i=2;help[i-1]<=1200;i++) help[i]=help[i-1]+i;
	scanf("%d",&x);
	int i,k=2;
	while(x>=help[k]) k++; k--;
	for(i=2;i<=k;i++) tosum[++cnt]=i+(i>(k-x+help[k]));
	if(x==help[k+1]-1) tosum[cnt]++;
	
	weis=1; arr[1]=1;
	for(i=1;i<=cnt;i++)
	{
		for(int j=1;j<=weis;j++) arr[j]*=1LL*tosum[i];
		for(int j=1;j<weis;j++)
			arr[j+1]+=arr[j]/10,arr[j]%=10;
		if(arr[weis]>10) arr[weis+1]=arr[weis]/10,arr[weis]%=10,weis++;
	}
	for(int j=weis;j>=1;j--) printf("%lld",arr[j]);puts("");
}