bzoj 1263 //1263: [SCOI2006]整数划分 //在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=1263
更多题解,详见https://blog.csdn.net/mrcrack/article/details/90228694BZOJ刷题记录
//1263: [SCOI2006]整数划分
//在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=1263
// 第2行输出最大乘积的前100位,题意比较明确,需要高精度算法
//乘积最大位数如何确定
//此文https://blog.csdn.net/PoPoQQQ/article/details/43602567思路不错,摘抄如下,有修改
/*
结论:
如果n是3的倍数 那么将n划分成n/3个3是最优的
如果n是3的倍数+1 那么将n划分成(n-4)/3个3和两个2是最优的
如果n是3的倍数+2 那么将n划分成(n-2)/3个3和1个2是最优的
证明是有的
考虑不是划分成整数,而是划分成任意实数
设我们将n划分成了x个正实数之和
易知当这x个数相等时答案是最优的
那么每个数都是n/x,答案是(n/x)^x
设y=(n/x)^x
则有lny=x[ln(n)-ln(x)]
两侧求导可得y'=(n/x)^x * ( ln(n) - ln(x) - 1 )
补充求导过程:
(lny)'=(x(ln(n)-ln(x)))'
y'/y=(x)'(ln(n)-ln(x))+x(ln(n)-ln(x))'
y'/y=ln(n)-ln(x)+x(0-1/x)
y'/y=ln(n)-ln(x)-1
带入y=(n/x)^x
y'=(n/x)^x * ( ln(n) - ln(x) - 1 )
当x=n/e时y‘取0 此时乘积最大
补充:
y'=(n/x)^x * ( ln(n) - ln(x) - 1 )=0 导数为0,出现极值
即
ln(n)-ln(x)-1=0
ln(n)-ln(x)-ln(e)=0
ln(n)-ln(e)-ln(x)=0
ln(n/e)-ln(x)=0
ln(n/e)=ln(x)
x=n/e
因此每个数要尽量靠近e才能使答案最大
现在考虑整数 离e最近的整数是3 因此要把n尽量分成3 不足的用2补齐 这样可以保证是最优的。
*/
//此文https://blog.csdn.net/PoPoQQQ/article/details/43602567代码也写得优秀
//有了上述算法,该题编起来就简单了,高精度*低精度
//担心超时,测试了31000
//1s能完成
//样例通过,提交Wrong_Answer.
//重新读题,发现"第2行输出最大乘积的前100位",会错意了,第2行输出有问题
//修改,提交AC.2019-8-22 16:48
#include <stdio.h>
#include <string.h>
#define maxn 5100
int ans[maxn];
void mul(int x){
int i;
for(i=1;i<=ans[0];i++)ans[i]*=x;
for(i=1;i<=ans[0];i++)ans[i+1]+=ans[i]/10,ans[i]%=10;
if(ans[i])ans[0]=i;
}
int main(){
int n,i;
memset(ans,0,sizeof(ans));
scanf("%d",&n);
ans[1]=1,ans[0]=1;//ans[0]储存数据长度
switch(n%3){//10≤n≤31000
case 0:
for(i=3;i<=n;i+=3)mul(3);//n=3,6,9,12可以尝试得出for的循环规律
break;
case 1:
for(i=7;i<=n;i+=3)mul(3);//n=4,7,10可以尝试得出for的循环规律
mul(4);
break;
case 2:
for(i=5;i<=n;i+=3)mul(3);//n=2,5,8,11可以尝试得出for的循环规律
mul(2);
break;
}
printf("%d\n",ans[0]);
if(ans[0]<=100)
for(i=ans[0];i>=1;i--)printf("%d",ans[i]);
else
for(i=ans[0];i>ans[0]-100;i--)printf("%d",ans[i]);
printf("\n");
return 0;
}