zoukankan      html  css  js  c++  java
  • 最大乘积

    将一个整数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;
    }
  • 相关阅读:
    关于Mac上的开发工具
    关于VS2008和VS2013中字体的选择
    实验四 使用ASP.NET内置对象 总结
    实验三 使用ASP.NET常用服务器控件 总结
    实验二 C#程序设计 总结
    实验一 ASP.NET应用环境配置 总结
    关于PHP.INI中的错误ERROR报告级别设置
    获取当前网址跟目录
    PHP获取站点根目录
    php 上传图片
  • 原文地址:https://www.cnblogs.com/hsqdboke/p/2458954.html
Copyright © 2011-2022 走看看