最大乘积
题目描述
一个正整数一般可以分为几个互不相同的自然数的和,如 \(3=1+2\),\(4=1+3\),\(5=1+4=2+3\),\(6=1+5=2+4\)。
现在你的任务是将指定的正整数 \(n\) 分解成若干个互不相同的自然数的和,且使这些自然数的乘积最大。
输入输出格式
输入格式
只一个正整数 \(n\),(\(3 \leq n \leq 10000\))。
输出格式
第一行是分解方案,相邻的数之间用一个空格分开,并且按由小到大的顺序。 第二行是最大的乘积。
输入输出样例
输入样例 #1
10
输出样例 #1
2 3 5
30
分析
此题的关键是抓住和同近积大的原理。
和同近积大:两个数的和一定,差小,积大。
也就是说,假设\(a \ge b\),那么\((a + 1) \times (b - 1) < a \times b\)。
简证:\((a + 1) \times (b - 1) = a \times b + b - a - 1\),而既然\(a \ge b\),那么\(b - a \le 0\)。最后这个算式还有个减一,因此\((a + 1) \times (b - 1) < a \times b\)。
我们考虑在两个的和同近积大原理上进行扩展。因为此题要求所有数字互不相同,我们也想要尽可能多的因数,然后他们还越接近越好。于是如此,我们就可以构造一个由2开始的自然数数列,然后一直求和,直到这个和大于了\(n\)。
为什么从\(2\)开始?如果从\(1\)开始的话,\(1\)浪费了这个数和的一块,却对整体的积一点用都没用。血亏!
但是此时和是大于\(n\)的,那么假设多出来的是\(k\)吧,那么此时就把值为\(k\)的那项移出去。此时得到的就是正确的数列——
吗?
- 不,你忘考虑了\(k = 1\)的情况。这种情况下的最优解是去掉开头的2,然后给末尾项加1。
- 你还忘考虑了\(n = 3,4\)的情况,此时的解就是\(n\)本身。
其实我有一个问题,就是上述解法是我根据不严谨的思路推出来的,我还没有想好一种严格证明的方案,有小伙伴能告诉我吗?我感激不尽。
哦对了,这道题还需要高精度哦,别忘了,\(n \le 10000\),不开高精见祖宗呢。
代码
本代码采用了高精模板。link
/*
* @Author: crab-in-the-northeast
* @Date: 2020-04-02 00:58:54
* @Last Modified by: crab-in-the-northeast
* @Last Modified time: 2020-04-02 01:10:27
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cassert>
#include <vector>
int max(int a,int b) {
return a > b ? a : b;
}
struct ubigint {
typedef unsigned long long ull;
static const int base = 100000000;
static const int width = 8;
std :: vector<int> s;
ubigint& clear_zero() {
while(!s.back() && s.size() > 1) s.pop_back();
return *this;
}
ubigint(ull num = 0) {*this = num;}
ubigint(std :: string str) {*this = str;}
ubigint& operator = (ull num) {
s.clear();
do {
s.push_back(num % base);
num /= base;
}while(num);
return *this;
}
ubigint& operator = (const std :: string& str) {
s.clear();
int x;
int len = (str.length() - 1) / width + 1;
for(int i = 0; i < len; i++) {
int endidx = str.length() - i * width;
int startidx = max(0, endidx - width);
int x;
sscanf(str.substr(startidx, endidx - startidx).c_str(), "%d", &x);
s.push_back(x);
}
return (*this).clear_zero();
}
bool operator < (const ubigint& b) const {
if(s.size() != b.s.size()) return s.size() < b.s.size();
for(int i = s.size() - 1; i >= 0; i--)
if(s[i] != b.s[i])
return s[i] < b.s[i];
return false;
}
bool operator > (const ubigint& b) const {return b < *this; }
bool operator <= (const ubigint& b) const {return !(b < *this);}
bool operator >= (const ubigint& b) const {return !(*this < b);}
bool operator == (const ubigint& b) const {return !(b < *this) && !(b > *this);}
bool operator != (const ubigint& b) const {return b < *this || *this < b;}
ubigint operator + (const ubigint& b) const {
ubigint res;
res.s.clear();
for(int i = 0, x = 0; x || i < s.size() || i < b.s.size(); i++, x /= base) {
if(i < s.size()) x += s[i];
if(i < b.s.size()) x += b.s[i];
res.s.push_back(x % base);
}
return res.clear_zero();
}
ubigint operator - (const ubigint& b) const {
assert(*this >= b);
ubigint res;
res.s.clear();
for(int i = 0, last = 0;last || i < s.size() || i < b.s.size();i++) {
int x = s[i] + last;
if(i < b.s.size()) x -= b.s[i];
if(x < 0) {
last = -1;
x += base;
}else last = 0;
res.s.push_back(x);
}
return res.clear_zero();
}
ubigint operator * (const ubigint& b) const {
std :: vector<ull> tmp(s.size() + b.s.size(),0);
ubigint res;
res.s.clear();
for(int i = 0; i < s.size(); i++)
for(int j = 0; j < b.s.size(); j++)
tmp[i + j] += ull(s[i]) * b.s[j];
ull last = 0;
for(int i = 0; last || i < tmp.size(); i++) {
ull x = tmp[i] + last;
res.s.push_back(x % base);
last = x / base;
}
return res.clear_zero();
}
int midsearch(const ubigint& b, const ubigint& m) const {
int l = 0, r = base - 1;
while(1) {
int mid = l + r >> 1;
if(b * mid <= m && b * (mid + 1) > m) return mid;
if(b * mid <= m) l = mid;
else r = mid;
}
}
ubigint operator / (const ubigint& b) const {
assert(b > 0);
ubigint res = *this, mod;
for(int i = s.size() - 1; i >= 0; i--) {
mod = mod * base + s[i];
res.s[i] = midsearch(b, mod);
mod -= b * res.s[i];
}
return res.clear_zero();
}
ubigint operator % (const ubigint& b) const {
assert(b > 0);
ubigint res = *this, mod;
for(int i = s.size() - 1; i >= 0; i--) {
mod = mod * base + s[i];
res.s[i] = midsearch(b, mod);
mod -= b * res.s[i];
}
return mod.clear_zero();
}
ubigint& operator += (const ubigint& b) {*this = *this + b; return *this;}
ubigint& operator -= (const ubigint& b) {*this = *this - b; return *this;}
ubigint& operator *= (const ubigint& b) {*this = *this * b; return *this;}
ubigint& operator /= (const ubigint& b) {*this = *this / b; return *this;}
ubigint& operator %= (const ubigint& b) {*this = *this % b; return *this;}
friend std :: istream& operator >> (std :: istream& in, ubigint& x) {
std :: string str;
if(!(in >> str)) return in;
x = str;
return in;
}
friend std :: ostream& operator << (std :: ostream& out, ubigint x) {
out << x.s.back();
for(int i = x.s.size() - 2; i >= 0; i--) {
char buf[20];
sprintf(buf, "%08d", x.s[i]);
for(int j = 0; j < strlen(buf); j++)
out << buf[j];
}
return out;
}
};
int main() {
int n;
std :: cin >> n;
int sum = 0, to;
if(n <= 4) {
std :: cout << n << std :: endl << n << std :: endl;
return 0;
}
for(int i = 2; sum <= n; i++) {
sum += i;
to = i;
}
ubigint ans = 1;
for(int i = 2; i <= to; i++) {
if(sum - n == 1) {
if(i == 2) continue;
if(i == to) {
std :: cout << i + 1 << ' ';
ans *= (i + 1);
break;
}
}
if(i != sum - n) {
std :: cout << i << ' ';
ans *= i;
}
}
std :: cout << std :: endl << ans << std :: endl;
return 0;
}