洛谷P1249 最大乘积【数论+贪心

原题:https://www.luogu.com.cn/problem/P1249

参考题解:https://www.luogu.com.cn/problemnew/solution/P1249

题目描述

一个正整数一般可以分为几个互不相同的自然数的和,如 3=1+23=1+2,4=1+34=1+3,5=1+4=2+351+4=2+3,6=1+5=2+46=1+52+4。

现在你的任务是将指定的正整数 nn 分解成若干个互不相同的自然数的和,且使这些自然数的乘积最大。

输入格式

只一个正整数 nn,(3 \leq n \leq 100003n10000)。

输出格式

第一行是分解方案,相邻的数之间用一个空格分开,并且按由小到大的顺序。

第二行是最大的乘积。

输入输出样例

输入 #1
10
输出 #1
2 3 5
30


注意高精度

我刚开始想的时候居然搞递归。。。。。我当时想,对于一个数,如果是一次分割,那么分割的两个数越相近结果越大。所以我每次都分为两个,一直到不能分或者有重复为止。用set记录已经得到的结果。
但是这样一些普通的测试数据能过,交到oj上全wa。。。

后来看到题解:https://www.luogu.com.cn/problemnew/solution/P1249

本题要先用简单的数论和贪心找到最优解的组成方法,再用高精度乘法求积。

以2004为例,由于把2004分拆成若干个互不相等的自然数的和的分法只有有限种,因而一定存在一种分法,使得这些自然数的乘积最大。

若1作因数,则显然乘积不会最大。把2004分拆成若干个互不相等的自然数的和,因数个数越多,乘积越大。为了使因数个数尽可能地多,我们把2004分成2+3…+n直到和大于等于2004。

若和比2004大1,则因数个数至少减少1个,为了使乘积最大,应去掉最小的2,并将最后一个数(最大)加上1。

若和比2004大k(k≠1),则去掉等于k的那个数,便可使乘积最大。

例如15:s=2+3+4+5+6刚好大于15,s-15=5,所以把5去掉。

又例如13:s=2+3+4+5刚好大于13,s-13=1,所以去掉2,并把5加1,即3 4 6。


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%。

今天也学到了新知识。TAT

代码:
#include <bits/stdc++.h>
//#define LOCAL
using namespace std;
typedef long long ll;

set<int>number;
vector<ll> result;

const ll BASE=1e8;
string tostring(ll num){
    string t="";
    while(num>0){
        t=(char)(num%10+'0')+t;
        num/=10;
    }
    while(t.size()<8) t="0"+t;
    return t;
}


int main() {
#ifdef LOCAL
ifstream fin("1.txt");
streambuf*p;
p=cin.rdbuf(fin.rdbuf());
#endif // LOCAL
int n;
while(cin>>n){
    number.clear();

    int sum=0;
    int i=1;
    while(sum<n){
        i++;
        sum+=i;
        number.insert(i);
    }
    int rubbish=sum-n;
    if(rubbish==1){
        number.erase(2);
        number.erase(i);
        number.insert(i+1);
    }else{
        number.erase(rubbish); 
    }

    //输出set里的所有数据
    for(set<int>::iterator it=number.begin();it!=number.end();it++){
        if(it!=number.begin()) cout<<" ";
        cout<<*it;
    }
    cout<<endl;


    result.clear();
    result.push_back(1);

    //高精度乘法
    for(set<int>::iterator it=number.begin();it!=number.end();it++){
        ll more=0;
        for(int unsigned j=0;j<result.size();j++){
            ll temp=((ll)(*it)*result[j])+more;
            more=temp/BASE;
            result[j]=temp%BASE;
        }
        if(more>0) result.push_back(more);
    }

    //高精度输出
    for(int unsigned i=result.size();i>0;i--){
        if(result.size()==i) cout<<result[i-1];
        else{
            cout<<tostring(result[i-1]);
        }
    }
    cout<<endl;
}




#ifdef LOCAL
fin.close();
#endif // LOCAL
}

  




posted @ 2020-04-16 13:50  反射狐  阅读(703)  评论(0)    收藏  举报