天明
题目描述
话说,自从天明那次看到高月驾驶机关兽后,心里十分痒痒,于是找到高月,要她教自己驾驶机关兽。
高月:“我可是学了一年呐!”
而且,说实话,高月觉得以天明的智商,机关术可能有点……
于是乎,天明决定向月儿证明,自己的智商没有问题!
天明四处打听,终于打听到了一种测智商的方法:将一个给定的数分成若干个互不
相等的数的和,使得分成的数的乘积最大,分成的数的乘积代入到一个正相关的函
数中所得的值就是自己的智商。
所以,你需要帮助天明,让他可以为自己开出一张“高智商”证明。(就是作弊
啦……)
输入
仅一行,一个整数 n,就是你要分解的那个数。(其中1 ≤ n ≤ 1000)
输出
一个整数,就是 n 分解成若干个互不相等的数的最大乘积。
样例输入
7
样例输出
12
分析
通过这道题教大家一个道理:NOIP模拟=打表找规律=变成爆破兵。 教大家学会打表找规律的方法:
打个分析表
首先随便写一个dfs得到一个分析表。
何谓分析表?
就此题而言,如果只打一个表记录n和对应的答案,即ans[7]=12; ans[8]=15;
或者ans[1234]={0,1,2,3,4,6……};
或者if(ans==7) return printf("12\n")*0;
这样的表是远远不够我们找规律的!至少也要想这个样子打表:
1->1 0 2->2 2 3->3 3 4->4 4 5->6 2*3 6->8 2*4 7->12 3*4 8->15 3*5 9->24 2*3*4 10->30 2*3*5 11->40 2*4*5 12->60 3*4*5 13->72 3*4*6 14->120 2*3*4*5 15->144 2*3*4*6 16->180 2*3*5*6 17->240 2*4*5*6 18->360 3*4*5*6 19->420 3*4*5*7 20->720 2*3*4*5*6 21->840 2*3*4*5*7 22->1008 2*3*4*6*7 23->1260 2*3*5*6*7 24->1680 2*4*5*6*7 25->2520 3*4*5*6*7 26->2880 3*4*5*6*8 27->5040 2*3*4*5*6*7 28->5760 2*3*4*5*6*8 29->6720 2*3*4*5*7*8 30->8064 2*3*4*6*7*8 31->10080 2*3*5*6*7*8 32->13440 2*4*5*6*7*8 33->20160 3*4*5*6*7*8 34->22680 3*4*5*6*7*9 35->40320 2*3*4*5*6*7*8 36->45360 2*3*4*5*6*7*9 37->51840 2*3*4*5*6*8*9 38->60480 2*3*4*5*7*8*9 39->72576 2*3*4*6*7*8*9 40->90720 2*3*5*6*7*8*9 41->120960 2*4*5*6*7*8*9 42->181440 3*4*5*6*7*8*9 43->201600 3*4*5*6*7*8*10 44->362880 2*3*4*5*6*7*8*9 45->403200 2*3*4*5*6*7*8*10 46->453600 2*3*4*5*6*7*9*10 47->518400 2*3*4*5*6*8*9*10 48->604800 2*3*4*5*7*8*9*10 49->725760 2*3*4*6*7*8*9*10 50->907200 2*3*5*6*7*8*9*10 51->1209600 2*4*5*6*7*8*9*10 52->1814400 3*4*5*6*7*8*9*10 53->1995840 3*4*5*6*7*8*9*11 54->3628800 2*3*4*5*6*7*8*9*10 55->3991680 2*3*4*5*6*7*8*9*11 56->4435200 2*3*4*5*6*7*8*10*11 57->4989600 2*3*4*5*6*7*9*10*11 58->5702400 2*3*4*5*6*8*9*10*11 59->6652800 2*3*4*5*7*8*9*10*11 60->7983360 2*3*4*6*7*8*9*10*11
不要问我为什么在引用块里套代码块
整体观察与分段对比
整体观察
这里才开始讲题
发现,不算上1,好像是把一个数拆得越散,乘积就会越大。
分段对比
比方说本题很明显地看得出乘数个数的层次,即由几个数乘起来。
那么我们只要相信反正我是在找规律,这个层次推出来的规律一定适用于其它层次地集中火力搞某一个比较一般又比较好处理的层次。
不信也没关系,求出来一个规律再代入其它层次去看就是了。
如果分不出层次,就试试递推吧;如果分出了层次,就把它当做分段递推吧。
这里才正式开始讲题
就这个题而言,选一个中间一点的层次:
27->5040 2*3*4*5*6*7 28->5760 2*3*4*5*6*8 29->6720 2*3*4*5*7*8 30->8064 2*3*4*6*7*8 31->10080 2*3*5*6*7*8 32->13440 2*4*5*6*7*8 33->20160 3*4*5*6*7*8 34->22680 3*4*5*6*7*9 35->40320 2*3*4*5*6*7*8
发现,27~34,都是6个数相乘,且正好27=2+3+4+5+6+7,27所对应的答案就是2*3*4*5*6*7=5040
。而28的答案是2*3*4*5*6*8
。
2*3*4*5*6*7 2*3*4*5*6*8 (最后一个由7变到8) 2*3*4*5*7*8 (倒数第二个从6变到7) 2*3*4*6*7*8 (倒数第三个也加了1) 2*3*5*6*7*8 (倒数第四个也加了1) 2*4*5*6*7*8 (3+1=4) 3*4*5*6*7*8 (2+1=3) 3*4*5*6*7*9 (每个数都加了一以后,最后一位再加一个一) 2*3*4*5*6*7*8 (35=2+3+4+5+6+7+8,答案是2*3*4*5*6*7*8)
是不是有点感觉了?
再把这个猜想在其它层次里看,发现正好合适,我应该想出了正确的规律耶。
↑是非常重要的,因为找规律的本质就是猜想猜想猜想猜想猜想猜想猜想猜想猜想猜想猜想猜想猜想吧。而猜想必须要经得起石剑实践的检验才行。
最后成型的猜想就是这样子的:
(考试的时候写的,比较很模糊不清,见谅)
打表发现把给定的数拆得更散答案更大。 当然,1是肯定不能拿出来的。 总之就是不管1,优先使项数最多。 只需要预处理一个2+3+4+5+6+......的数列出来然后找n在哪两个数之间即可,这个甚至不需要lower_bound,直接枚举。 下面是根据打表观察出的结论: 记上述数列为A,A[i]=2+3+......+i,则: ①若n=A[t],则ans=t!即2*3*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*4*5*...*(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("");
}