洛谷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+35=1+4=2+3,6=1+5=2+46=1+5=2+4。
现在你的任务是将指定的正整数 nn 分解成若干个互不相同的自然数的和,且使这些自然数的乘积最大。
输入格式
只一个正整数 nn,(3 \leq n \leq 100003≤n≤10000)。
输出格式
第一行是分解方案,相邻的数之间用一个空格分开,并且按由小到大的顺序。
第二行是最大的乘积。
输入输出样例
输入 #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 }