整数划分

题目描述

经过第一轮的游戏,不少同学将会获得圣诞特别礼物,但这时细心的数学课代表发现了一个问题:留下来的人太多而使礼物数量可能不够,为此,加试了一道数学题:将一个正整数n分解成若干个互不相等的正整数的和,使得这些数的乘积最大,当主持人报出一个n后,请你立即将这个最大值报出来,现请你帮你的好友编一个程序来解决这个问题。

输入格式

输入中只有1个数n(其中1<=n<=1000)。

输出格式

输出中也是一个数,是乘积的最大值。

样例输入

7

样例输出

12


此题时将整数M划分成N个不同整数  使N个整数乘积最大 (Wikioi 2612 / RQNOJ 269 / TYVJ 1260)

首先我们不会分解出1 

将M划分成1和(M-1)  乘积不会比M大

1.对于小于4的数 无法将它划分出乘积大于自身的数 所以就不划分

2.当M=4时 2+2=2*2 我们可以划分也可以不划分 为了方便 将它划分成2+2

3.当M>4时 保证不重复和不分解出1  分解出的数越多越好

   M>4时 可以分解成2个整数乘积大于M

    


为了分解更多的数

1.可以将M分解成2+3+...+k一直到和大于等于M

   若和=M 则此方案为最佳

   否则必须删掉一个数

   当比M大1时 删掉2 并将(k-1)变成k

   当比M大w(w!=1)时 删掉w

2.分解成2+3+...+k<=M使得再加上k+1时大于M

   则对于差w 将w分成w个1  从大到小加到分解的数上

   若w>k-1 则加完一边后再继续从大到小加1

   如分解6

   2+3<6<2+3+4

   2+3+4-6=3

   将3分成3个1

   加到3 2 上 还剩一个1

   再加到4 3中的3上

   由大到小的顺序  是为了保证不相同


代码如下


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int s[11111];
int ans[1111];

int m,a,b,c,n;

void print(int ans[1111])
{
    int a;
    for(a=1000;a>1;a--)
    if(ans[a])break;
    while(a)
    {
        cout<<ans[a];
        a--;
    }
}

void jinwei(int ans[1111])
{
    int i;
    for(int i=1;i<=1000;i++)
    if(ans[i]>=10)
    {
        ans[i+1]=ans[i+1]+ans[i]/10;
        ans[i]%=10;
    }
}

void calc()
{
    int a,b;
    ans[1]=1;
    for(a=1;a<=n;a++)
    {
        for(b=1;b<=500;b++)
        ans[b]=ans[b]*s[a];
        jinwei(ans);
    }
}


int main()
{
    cin>>m;
    for(a=1;m>s[a-1];a++)
    {
        s[a]=min(a+1,m);
        m-=s[a];
        if(m<=s[a])break;
    }
    n=a;
    
    while(m)
    {
        for(a=n;a>=1;a--)
        {
            s[a]++;
            m--;
            if(m<=0)break;
        }
    }
    calc();
    print(ans);
    return 0;
}


   



对于可相同的整数划分(VIJOS 1033)

将整数M划分成N个整数 使N个整数乘积最大(Wikioi 3179)

将M划分成1和(M-1)  乘积不会比M大  故不分解出1

因此

1.对于小于4的数 无法将它划分出乘积大于自身的数 所以就不划分

2.当M=4时 2+2=2*2 我们可以划分也可以不划分 为了方便 将它划分成2+2

3.当M>4时 可证明M分解成若干整数的和 他们的积大于M

   考虑分解成2个数的情况

   当M为偶数时  (M/2)^2>M 解得M>4

   当M为奇数时  ((M+1)/2)*((M-1)/2)>M 解得M>2*5^(1/2)

   因此M>4时 可以分解成2个整数乘积大于M 需要将它分解

   M>4时 令M=x+(M-x)

   考虑y=x*(M-x)  y表示数乘积比M大的值

   y为二次函数 开口向下  在M/2时取到最大值 在(0,M/2)单调递增 在(M/2,M)单调递减

   所以M为偶数时 分解成M/2+M/2

   M为奇数时 分解成(M+1)/2+(M-1)/2

   然后对分解后的数也尝试考虑1.2.3


这样做后 发现最后分解的数都为2和3

由于2*2*2<3*3而2+2+2=3+3

所以每分解成3个2 我们将它变成2个3

这样就可以求出最大的乘积  


#include<iostream>
#include<cstdio>
using namespace std;
int m,a,b,z[1011];
void print()
{
    int a;
    for(a=1000;a>1;a--)if(z[a])break;
    while(a)
    {
        cout<<z[a];a--;
    }
    cout<<'\n';
}

void jinwei()
{
    for(int a=1;a<=1000;a++)
    if(z[a]>=10)
    {
        z[a+1]=z[a+1]+z[a]/10;
        z[a]%=10;
    }
}

void calc()
{
    z[1]=1;
    while(b)
    {
        z[1]*=2;
        b--;
    }
    while(a)
    {
        for(int k=1;k<=1000;k++)z[k]*=3;
        jinwei();
        a--;
    }
    print();
}

int main()
{
    cin>>m;
    if(m<=4)
    {
        cout<<m<<'\n';
        return 0;
    }
    while(m%3!=0)
    {
        b++;
        m-=2;
    }
    a=m/3;
    calc();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值