題目
描述
今年是國際數學聯盟確定的“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;
}