\(\色{赤} {\ mathcal {説明}} \)
今年は、「決定するために国際数学連合です\(2000 \)も、---世界数理年」の有名な数学者、氏は華の誕生日と一致している\(90 \)周年。氏は華の故郷ジンタン、数学のクイズは、あなたの友人の、壮大な1の活動を組織し、\(XZ \)も参加する機会を持っています。活動は、すべてのプレイヤーのホストは、この一人の被験者のうち、活動に参加します:
長さがある\(N \)数字の文字列を、プレイヤーが使用が必要です\(K \)それはに乗算番目の\(K + 1 \)のポイントを見つけるために、部品、そのので\(K +1 \)生成物の一部を最大にすることができます。
次のように一方、プレイヤーが正しく質問の意味を理解することができるよう支援するために、司会者も例を引用しました:
数字列:\(312 \) 、\(N = 3 \) 、\(K = 1 \。)二つのタイムポイントシステムがあります。
\(\ = 12 3回36 \である。) 、(\ 31 \ 2 = 62であるタイムズ\である)この場合、結果は、被験体の要件に沿ったものである:\(31 \ 2 = 62であるタイムズ\です)
さて、あなたはあなたの友人を助ける\(XZ \)正しい答えを得るためにプログラムを設計します。
\(\色{赤} {\ mathcal {入力\形式}} \)
入力プログラムの二列:最初の行は、22点の自然数有している\(N、K \)を、2行目は長さである\(N \)数値文字列。
\(\色{赤} {\ mathcal {出力\フォーマット}} \)
結果は、入力の最大積に対して、画面に表示され、出力は、(自然数)を取得しなければなりません。
\(\色{赤} {\ mathcal {DATASIZE \契約}} \)
\(6≤N≤40,1≤K≤6\)
\(\色{赤} {\ mathcal {解決}} \)
リニアDP
注文\(DP [i]の[jは ] \) 前回表し\(私は\)文字を挿入\(J \)の列挙を取得するために最大の乗算積番目の\(J \)を挿入乗算目を位置(\(K \)の数字の後)が、伝達方程式が得られます。
\ [DP [I] [J] = \最大{DP [K] [J-1] * NUM(K + 1、i)は} \ \ \ \ \ \(iは当量Nを\ 2 \当量、1 \当量J \当量\分(I-1、K)、J \当量のK <I)\]
初期化\(DP [I] [0 ] = NUM iの当量のNを\(1、I)\ \ \(1つの\ 1当量)\)
\(\色{赤} {\ mathcal {コード}} \)
#include <bits/stdc++.h>
#define LL long long
#define reg register
using namespace std;
const int kN = 100;
LL dp[kN][kN];
string num;
int N, K;
LL Cut(int l, int r) {
LL ret = 0;
for (reg int i = l; i <= r; ++i)
ret = ret * 10 + num[i - 1] - '0';
return ret;
}
int main() {
scanf("%d%d", &N, &K);
cin >> num;
for (reg int i = 1; i <= N; ++i)
dp[i][0] = dp[i - 1][0] * 10 + num[i - 1] - '0';
for (reg int i = 2; i <= N; ++i)
for (reg int j = 1; j <= min(i - 1, K); ++j)
for (reg int k = j; k < i; ++k)
dp[i][j] = max(dp[i][j], dp[k][j - 1] * Cut(k + 1, i));
printf("%lld\n", dp[N][K]);
return 0;
}