題目連接:http://nyoj.top/problem/746
【題目描述】
《746-整數劃分(四)》
暑假來了,hrdv 又要留學校在參加ACM集訓了,集訓的生活很是Happy(ps:你懂得),但是他最近遇到了一個難題,讓他百思不得其解,他很是鬱悶。。親愛的你能幫幫他嗎?
問題是咱們常常見到的整數劃分,給出兩個整數 n , m ,要求在 n 中加入m - 1 個乘號,將n分紅m段,求出這m段的最大乘積
【輸入格式】
第一行是一個整數T,表示有T組測試數據
接下來T行,每行有兩個正整數 n,m ( 1<= n < 10^19, 0 < m <= n的位數)。
【輸出格式】
輸出每組測試樣例結果爲一個整數佔一行
【樣例輸入】
2
111 2
1111 2
【樣例輸出】
11
121
【題目分析】
涉及的知識點:區間動態規劃(區間DP)。
首先咱們來看,這道題目怎麼創建起它的狀態轉移方程呢?
咱們假設輸入的數字 a 一共有 n 爲,從高位到低位分別標記爲第1位,第2位,……,第n爲。
咱們用 dp[i][j] 表示 a 的前 i 位使用了 j 個乘號所獲得的最大的結果,用 num[L][R] 表示 a 從第L位到第R位所組成的數 那麼:
當j==0時:
dp[i][j]=num[1][i]
當j>0時:
dp[i][j] = max(dp[k][j-1] + num[k+1][i]), j≤k<i。
據此,咱們能夠編寫代碼以下:ios
#include <iostream> #include <algorithm> using namespace std; const int maxn = 22; int n, m, T; long long a; long long ten_pow[20]; // ten_pow[i] 表示 10 的 i 次方 long long dp[maxn][maxn]; void init_ten_pow() { // 用於初始化ten_pow[] ten_pow[0] = 1; for (int i = 1; i <= 19; i ++) ten_pow[i] = ten_pow[i-1] * 10LL; } void get_digits() { // 用於得到a的位數的函數 n = 1; long long tmp = 10LL; while (a / tmp) { tmp *= 10LL; n ++; } } long long get_num(int L, int R) { // 這個函數用於求數組a從左往右數第L位到第R位這個區間範圍對應的數 return a / ten_pow[n-R] % ten_pow[R-L+1]; } int main() { cin >> T; init_ten_pow(); while (T --) { fill(dp[0], dp[0]+maxn*maxn, 0); cin >> a >> m; get_digits(); for (int i = 1; i <= n; i ++) { // i 表示數 a 從左往右數第i位,從1開始 dp[i][0] = get_num(1, i); for (int j = 1; j < m && j < i; j ++) { // j 表示 第 1 至 i 位,而且以第i位結尾的,使用了j次乘號能獲得的最大值 for (int k = j; k < i; k ++) { dp[i][j] = max(dp[i][j], dp[k][j-1] * get_num(k+1, i)); } } } cout << dp[n][m-1] << endl; } return 0; }