整数划分(四)
时间限制:1000 ms | 内存限制:65535 KB
难度:3
- 描述
-
暑假来了,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
- 来源
- 经典题目
- 上传者
- TC_胡仁东
- 区间dp。
- 开始我被样例忽悠了,以为所有的整数都是1111....这种形式的,后来才知道并不是。
-
根据区间dp的思想,我们定义dp [ i ] [ j ]为从开始到 i 中加入 j 个乘号得到的最大值。
那么我们可以依次计算加入1----m-1个乘号的结果
而每次放入x个乘号的最大值只需枚举第x个乘号的放的位置即可
dp [ i ] [ j ] = max(dp [ i ] [ j ] , dp [ k ] [ j-1 ] * a [ k] [ i - 1]);
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> using namespace std; #define ll long long #define repu(i, a, b) for(int i = a; i < b; i++) #define repd(i, a, b) for(int i = b; i >= a; i--) #define sfi(n) scanf("%d", &n) #define pfi(n) printf("%d\n", n) #define _cle(m, a) memset(m, a, sizeof(m)) ll a[20][20]; ll dp[20][20]; char s[21]; int n, k; void init() { _cle(a, 0); repu(i, 0, n) repu(j, i, n) repu(k, i, j + 1) a[i][j] = a[i][j] * 10ll + (ll)(s[k] - '0'); } int main() { int T; sfi(T); while(T--) { _cle(dp, 0); scanf("%s", s); n = strlen(s); init(); sfi(k); k--; repu(i, 1, n + 1) { dp[i][0] = a[0][i - 1]; repu(j, 1, k + 1) repu(p, 1, i) dp[i][j] = max(dp[i][j], dp[p][j - 1] * a[p][i - 1]); } printf("%lld\n", dp[n][k]); } return 0; }