【a602】最大乘积

Time Limit: 1 second
Memory Limit: 32 MB

【问题描述】

一个正整数一般可以分为几个互不相同的自然数的,如3=1+2,4=1+3,5=1+4=2+3,6=1+5=2+4,…。
现在你的任务是将指定的正整数n分解成若干个互不相同的自然数的和,且使这些自然数的乘积最大。

【输入格式】

仅一行,正整数n(3≤n≤10000)。

【输出格式】

共两行。第一行是分解方案,相邻的数之间用一个空格分开,并且按从小到大的顺序。第二行是最大的乘积。

【输入样例】

10

【输出样例】

2 3 5
30

【题目链接】:http://noi.qz5z.com/viewtask.asp?id=a602

【题解】

注意这里是说分解成若干个不同的;不能有相同的;
首先考虑分解后的情况.
假设一个数字为h;
分解成两个部分a,h-a;
然后考虑它们的乘积与h的大小关系
令f(a)=a*(h-a)-h
=a*h-a*a-h
=(a-1)*h-a*a
这里让a< h/2(因为要不同嘛,就假设a< h-a呗->a< h/2)
则h>2*a
则f(a)>(a-1)*2a-a*a
->f(a)>a*a-2*a;
->f(a)>a(a-2);
也就是说如果a>=2的话
f(a)>a(a-2)>=0
即f(a)>0
也即a*(h-a)>h
所以如果分成的若干个不同的数,它们都大于1的话,那么分成的乘积肯定比原来的大;
这里;再展示一个事实;
设h=2*s
假设他分成了
s-1和s+1
那么乘积为s^2-1
如果分成了
s-2和s+2
那么乘积为s^2-4
也就是说分成的两个数a,b
它们的差的绝对值越小;
它们的乘积就相应地越大;
这样我们可以先选取连续的自然数
2,3,4,5….x
这里(2+x)*(x-1)/2<=n
然后令temp = n-(2+x)*(x-1)/2
如果tmep=0
那么因为是连续的自然数,那么它们的差肯定是最小的;(差都是1);
则直接输出2,3,4..x就好
如果temp>0;
那么就把temp平均地分配到前面的数字里面去;
当然你要从后往前一个一个地分配
比如
n=13
2 3 4
13-(2+3+4)=4
则分配两个1给4,然后2和3分别给它们分配一个1(在平均的情况下尽量先分配后面的)
->3 4 5
这样就能保证差的绝对值相对地小;
最后的成绩也就越大;
(在数学推导上的贪心?)
最后数字很大要写个高精度乘单精度;
(n=3和4的情况特判一下)

【完整代码】

#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
#define pb push_back
#define LL long long

const int MAXN = 100;

int n,now;
LL a[1000];
vector <LL> v;

int main()
{
    scanf("%d",&n);
    if (n==3 || n==4)
    {
        printf("%d %d\n%d",1,n-1,n-1);
        return 0;
    }
    v.pb(2);n-=2;now=3;
    while (n >= now)
    {
        n-=now;
        v.pb(now);
        now++;
    }
    now = v.size()-1;
    while (n)
    {
        v[now]++;
        now--;
        n--;
        if (now==-1)
            now = v.size()-1;
    }
    a[1] = 1;
    int le = 1,len = v.size();
    for (int i = 0;i <= len-1;i++)
    {
        int x = 0;
        for (int j = 1;j <= le;j++)
        {
            a[j] = a[j]*v[i] + x;
            x = a[j]/10;
            a[j]%=10;
        }
        while (x>0)
        {
            le++;
            a[le] = x;
            x = a[le]/10;
            a[le]%=10;
        }
    }
    for (int i = 0;i <= len-1;i++)
    {
        printf("%I64d",v[i]);
        if (i==len-1)
            puts("");
        else
            putchar(' ');
    }
    for (int i = le;i >= 1;i--)
        printf("%I64d",a[i]);
    return 0;
}
posted @ 2017-10-04 18:45  AWCXV  阅读(122)  评论(0编辑  收藏  举报