bzoj 1263 //1263: [SCOI2006]整数划分

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;
}
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值