题目
描述
今年是国际数学联盟确定的“2000――世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰90周年。在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友XZ也有幸得以参加。活动中,主持人给所有参加活动的选手出了这样一道题目:
设有一个长度为N的数字串,要求选手使用K个乘号将它分成K+1个部分,找出一种分法,使得这K+1个部分的乘积能够为最大。
同时,为了帮助选手能够正确理解题意,主持人还举了如下的一个例子:
有一个数字串:312, 当N=3,K=1时会有以下两种分法:
1) 3*12=36
2) 31*2=62
这时,符合题目要求的结果是:31*2=62
现在,请你帮助你的好朋友XZ设计一个程序,求得正确的答案。
输入
程序的输入共有两行:
第一行共有2个自然数N,K(6≤N≤40,1≤K≤6)
第二行是一个长度为N的数字串。
输出
结果显示在屏幕上,相对于输入,应输出所求得的最大乘积(一个自然数)。
输入样例
4 2
1231
输出样例
62
解题思路
直接搜索?复杂度
,记忆化之后貌似还可以过。
不过这是一道经典的dp问题(毕竟记忆化搜索和dp本质是一样的):
- dp状态: 表示前 位数字中插入 个乘号能得到的最大值
- dp方程: ,其中 表示原数字中第 位到第 位组成的数字
- dp顺序:从dp方程易知, 从小到大依次循环即可,一定要注意范围
- 边界条件:
,即前
位一个乘号也不加就是它本身
答案就是 了
注意,这道题需要用高精度!
代码技巧
- 我是用的string存储,从string里面提取一段连续子序列可以用
s.substr(pos, len)
提取出从pos开始的长度为len的一段string类型字符串 - 建议写高精度的题时用重载运算符的方式,这样可以先写一份无高精度的代码检验算法正确性,过了样例后改成高精度时十分方便
Code
#include<cstdio>
#include<vector>
#include<string>
#include<iostream>
using namespace std;
typedef long long LL;
struct BigInteger{
vector<int> a;
BigInteger(){ a.clear(); }
BigInteger operator = (LL x){
a.clear();
do{
a.push_back(x % 10);
x /= 10;
}while(x);
return *this;
}
BigInteger operator = (const string &s){
a.clear();
for(int i = s.size() - 1; i >= 0; i--)
a.push_back(s[i] - '0');
return *this;
}
BigInteger operator + (const BigInteger &B) const{
BigInteger C;
for(int i = 0, g = 0; ; i++){
if(i >= a.size() && i >= B.a.size() && !g) break;
int x = g;
if(i < a.size()) x += a[i];
if(i < B.a.size()) x += B.a[i];
C.a.push_back(x % 10);
g = x / 10;
}
return C;
}
BigInteger operator * (const BigInteger &B) const{
BigInteger C;
C.a.resize(a.size() + B.a.size());
for(int i = 0; i < a.size(); i++){
int g = 0;
for(int j = 0; j < B.a.size(); j++){
C.a[i+j] += g + a[i] * B.a[j];
g = C.a[i+j] / 10;
C.a[i+j] %= 10;
}
C.a[i+B.a.size()] = g;
}
while(C.a.size() > 1 && C.a.back() == 0) C.a.pop_back();
return C;
}
BigInteger operator += (const BigInteger &B){
*this = *this + B;
return *this;
}
bool operator < (const BigInteger &B) const{
if(a.size() != B.a.size()) return a.size() < B.a.size();
for(int i = a.size() - 1; i >= 0; i--)
if(a[i] != B.a[i])
return a[i] < B.a[i];
return false;
}
bool operator > (const BigInteger &B) const{ return B < *this; }
bool operator <= (const BigInteger &B) const{ return !(*this > B); }
bool operator >= (const BigInteger &B) const{ return !(*this < B); }
bool operator != (const BigInteger &B) const{ return (*this < B) || (*this > B); }
bool operator == (const BigInteger &B) const{ return !(*this != B); }
inline void print(){
for(int i = a.size() - 1; i >= 0; i--) printf("%d", a[i]);
putchar(10);
}
};
inline BigInteger max(BigInteger a, BigInteger b){ return a > b ? a : b; }
inline int min(int a, int b){ return a < b ? a : b; }
inline int max(int a, int b){ return a > b ? a : b; }
int n, K;
string S;
BigInteger dp[45][10], t;
int main(){
scanf("%d%d", &n, &K);
cin >> S;
for(int i = 1; i <= n; i++)
dp[i][0] = S.substr(0, i);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= K; j++){
if(j >= i) break;
for(int k = j; k < i; k++){
t = S.substr(k, i - k);
dp[i][j] = max(dp[i][j], dp[k][j-1] * t);
}
}
}
dp[n][K].print();
return 0;
}