最大乘积

将一个整数n分解成x个正整数(a1+a2+a3+...+ax=n)使它们的乘积(a1*a2*a3*...*ax)最大。
答案可能很大,输出对m取模后的结果。
—思路一:动态规划(DP)
—可以很容的思考出来动态转移方程
—用dp[i]代表当n=i的时候的最大乘积,于是:
—DP[i]=max(DP[i-j]*DP[j])
—动态规划的方法虽然可以解决该类问题,但是当n的值非常大的时候,dp数组都很难开的下,故不管是时间复杂度还是空间复杂度都高得惊人!
—
—于是需要新的思路。
—思路二:
—按照我们数学直觉,应该不难想到,分出来的这些a1,a2,a3…应该要相等才能让他们的积最大。
—/*小学的时候大家应该学过同样的周长,要让面积最大,则围成正方形是最好的选择(除了圆)*/
——
既然a1,a2,a3…都相等,那么可以假定x=a[i]
—于是乘积f(x)=x^(n/x)(x为正整数)
—现在问题转化为当x为何值的时候让f(x)最大
—我们可以假定g(x)=ln(f(x))=(n/x)*lnx
—很明显,当x让g(x)取最大的时候,f(x)也得到了最大值。于是我们可以对g(x)求一次导数
—
—g’(x)=(n-n*lnx)/(x^2)=[n*(1-lnx)]/(x^2)
—故我们可以看到,当x=e(2.71828……)时g(x)取得极大值。但是因为x为正整数,所以只有分别比较x=2以及x=3两种情况下的f(x)谁更大
—既然现在已经知道把一个数分为几个数的和,且让他们的积最大,就是要把他们尽可能多的分为2或者3,问题就进一步简化了。
—我们只需要举几个例子便可以证明x到底取2还是x取3使得乘积最大。
—6=2+2+2=3+3
—2*2*2=8
—3*3=9
—因为f(x)是对所有的n而言的,故如果一个例子成立就代表所有情况都成立!
—至此,最大乘积的问题就快结束了。但是还有一个问题,虽然知道了尽可能让n多分出几个3出来,但是总会有余数吧,余数怎么处理呢?
—
—当考虑到当n=4的时候,如果分出3,就必然会得到一个1,显然不是最大的乘积(不是不符合刚刚的公式的推导,因为此时只有一个3,不能叫分成了几个相同的数)所以可以分情况考虑下
—在此,我们就不在做更多的证明了,乘积最大问题的一般处理如下:
—当n<=4的时候ans=n%m;
—当n>4且n%3==0的时候
—n全部分为3
—当n>4且n%3==1的时候
—把(n-4)的部分全部分为3,剩下的4直接乘上去
—当n>4且n%3==2的时候
—把(n-2)的部分全部分为3,剩下的2直接乘上去
—可以使用二分幂对m取余,把时间复杂度降为O(logn)的
 
 
#include<iostream>
using namespace std;
int solve(int n,int m)
{
    int i,s=1;
    if(n<=4)return     n%4;
    else
    {
        if(n%3==0)
        {
         for(i=1;i<=n/3;i++)
             s=s*3%m;
         return s;
        }
        else if(n%3==1)
        {
            for(i=1;i<=(n-4)/3;i++)
              s=s*3%m;
              return s*4%m;
        }
        else 
        {
            for(i=1;i<=(n-2)/3;i++)
              s=s*3%m;
              return s*2%m;
        }
    }

}
int main()
{
    int n,m;
    freopen("d:\\1.txt","r",stdin);
    while(scanf("%d%d",&n,&m)!=EOF&&(n||m))
    {
        cout<<solve(n,m)<<endl;
    }
    
    return 0;
}
原文地址:https://www.cnblogs.com/hsqdboke/p/2458954.html