P4157 [SCOI2006]整数划分 (数学推导+大数)

本文介绍了如何利用数学技巧,如均值不等式和对数分析,解决一道关于将正整数拆分为多个部分以最大化乘积的问题。通过讨论n对3的余数,作者给出了一个简单的算法,优先选择3和2的组合,展示了如何在有限时间内找到最优解。

原题题面

读入一个正整数nnn10≤n≤3100010≤n≤3100010n31000)。要求将nnn写成若干个正整数之和,并且使这些正整数的乘积最大。

例如,n=13n=13n=13,则当n表示为4+3+3+34+3+3+34+3+3+3(或2+2+3+3+32+2+3+3+32+2+3+3+3)时,乘积=108108108为最大。

输入格式

只有一个正整数nnn10≤n≤3100010≤n≤3100010n31000

输出格式

第1行输出一个整数,为最大乘积的位数。
第2行输出最大乘积的前100位,如果不足100位,则按实际位数输出最大乘积。
(提示:在给定的范围内,最大乘积的位数不超过5000位)。

输入样例

13

输出样例

3
108

题面分析

简单概括一下就是:已知∑xi=N\sum{x_i}=Nxi=N,求max{∏xi}max\{\prod{x_i}\}max{xi}.
看到∑xi\sum{x_i}xi∏xi\prod{x_i}xi很容易 就能想到均值不等式。
假设xix_ixinnn项,我们有
(∑xin)n≥∏xi(\frac{\sum{x_i}}{n})^n\geq\prod{x_i}(nxi)nxi
因为取到等号时,xix_ixi两两相等,因此xix_ixi要取的尽量平均,于是问题变成了求出
(∑xin)n=(Nn)n(\frac{\sum{x_i}}{n})^n=(\frac{N}{n})^n(nxi)n=(nN)n的最大值
我们可以用一些高数知识对它进行处理
y=(Nn)ny=(\frac{N}{n})^ny=(nN)n,两边套InInIn,得到Iny=nInN−nInnIny=nInN-nInnIny=nInNnInn
两边再求导,得到y′y=InN−Inn−1\frac{y'}{y}=InN-Inn-1yy=InNInn1(这里不再赘述为什么左边不是1y\frac{1}{y}y1)
移项得到y′=(InN−Inn−1)∗(Nn)ny'=(InN-Inn-1)*(\frac{N}{n})^ny=(InNInn1)(nN)n
y′=0y'=0y=0,即(InN−Inn−1)∗(Nn)n=0(InN-Inn-1)*(\frac{N}{n})^n=0(InNInn1)(nN)n=0
因为(Nn)n(\frac{N}{n})^n(nN)n必定大于0,故原式等价于求(InN−Inn−1)=0(InN-Inn-1)=0(InNInn1)=0,易知n=Nen=\frac{N}{e}n=eN
即把每个数尽可能地分成e
yyy(0,Ne](0,\frac{N}{e}](0,eN]上单调递增,[Ne,∞)[\frac{N}{e},\infty)[eN,)上单调递减。
但考虑到在整数范围,Ne\frac{N}{e}eN取不到,因此候选项有N2,N3\frac{N}{2},\frac{N}{3}2N,3N两个数,于是问题就转化为哪个优先取的问题。
代入方程,得到2N2<3N32^{\frac{N}{2}}<3^{\frac{N}{3}}22N<33N
如何证明?
两边取对数得到N2In2和N3In3\frac{N}{2}In2和\frac{N}{3}In32NIn23NIn3
注意到In22<In33\frac{In2}{2}<\frac{In3}{3}2In2<3In3
2N2<3N32^{\frac{N}{2}}<3^{\frac{N}{3}}22N<33N,
故优先取3,然后取2。 证毕。
于是这就变成了憨憨题,我们根据n mod 3n\ mod\ 3n mod 3的不同结果来讨论取的方法。
n mod 3=0n\ mod\ 3=0n mod 3=0时,无脑拿3,答案就是3N33^\frac{N}{3}33N
n mod 3=1n\ mod\ 3=1n mod 3=1时,拿出一个3变两个2,答案就是3N−13−1∗223^{\frac{N-1}{3}-1}*2^233N1122
n mod 3=2n\ mod\ 3=2n mod 3=2时,拿一个2之后全变3,答案就是3N−23∗23^{\frac{N-2}{3}}*233N22

AC代码(70ms)

import java.math.BigInteger;
import java.util.Scanner;

import static java.lang.Math.min;
/**
 * @author DrGilbert
 */
public class Main
{
    public static void main (String[] args)
    {
        Scanner cin = new Scanner (System.in);
        int n;
        while(cin.hasNext ())
        {
            n=cin.nextInt ();
            BigInteger ans;
            if(n%3==0)
            {
                ans=BigInteger.valueOf (3).pow ((n/3));
            }
            else if(n%3==1)
            {
                ans=BigInteger.valueOf (3).pow ((n/3-1)).multiply (BigInteger.valueOf (4));
            }
            else
            {
                ans=BigInteger.valueOf (3).pow ((n/3)).multiply (BigInteger.valueOf (2));
            }
            String ans1=ans.toString ();
            System.out.println (ans1.length ());
            for(int i=0;i<min(100,ans1.length ());i++)
            {
                System.out.print (ans1.charAt (i));
            }
            System.out.println ();
        }
    }
}

后记

用什么FFT,大数他不够香吗
DrGilbert 2020.10.4

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值