洛谷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
}

浙公网安备 33010602011771号