NYOJ 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的核心是区间合并,本题的dp[i][j]中的i,j不再是区间的起点和终点,起点始终是1,终点是i.
区
间
D
P
的
核
心
是
区
间
合
并
,
本
题
的
d
p
[
i
]
[
j
]
中
的
i
,
j
不
再
是
区
间
的
起
点
和
终
点
,
起
点
始
终
是
1
,
终
点
是
i
.
dp[i][j]:前i个字符插入j个乘号组成的最大值;
d
p
[
i
]
[
j
]
:
前
i
个
字
符
插
入
j
个
乘
号
组
成
的
最
大
值
;
转移方程:dp[i][j]=max(dp[i][j],dp[k][j−1]∗a[k+1][i]);
转
移
方
程
:
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
]
[
j
]
,
d
p
[
k
]
[
j
−
1
]
∗
a
[
k
+
1
]
[
i
]
)
;
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long LL;
const LL mod = 1e8;
const int MAXN = 20 + 10;
LL dp[MAXN][MAXN], a[MAXN][MAXN];
char str[MAXN];
int main() {
int T, m;
scanf("%d", &T);
while(T--) {
memset(a, 0, sizeof(a));
memset(dp, 0, sizeof(dp));
scanf("%s %d", str + 1, &m);
int len = strlen(str + 1);
for(int i = 1; i <= len; i++) { //预处理区间值
for(int j = i; j <= len; j++) {
a[i][j] += a[i][j - 1] * 10 + str[j] - '0';
//printf("%d -> %d -> %lld\n", i, j, a[i][j]);
}
}
for(int i = 1; i <= len; i++) { //赋初值
dp[i][0] = a[1][i];
}
for(int j = 1; j < m; j++) {
for(int i = j + 1; i <= len; i++) {
for(int k = j; k < i; k++) {
dp[i][j] = max(dp[i][j], dp[k][j - 1] * a[k + 1][i]);
}
}
}
printf("%lld\n", dp[len][m - 1]);
}
return 0;
}
数据范围太小了,直接暴力也能过;
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long LL;
const int MAXN = 20 + 10;
LL dp[MAXN][MAXN], a[MAXN][MAXN];
char str[MAXN];
int T, m, len;
LL ans;
void dfs(int i, int j, int k, LL cnt) {
if(k == m && j == len + 1) {
ans = max(ans, cnt);
return ;
}
if(k > m) return ;
if(j > len + 1) return ;
dfs(i, j + 1, k, cnt);
cnt *= a[i][j];
dfs(j + 1, j + 1, k + 1, cnt);
}
int main() {
scanf("%d", &T);
while(T--) {
ans = 0;
memset(a, 0, sizeof(a));
memset(dp, 0, sizeof(dp));
scanf("%s %d", str + 1, &m);
len = strlen(str + 1);
for(int i = 1; i <= len; i++) {
for(int j = i; j <= len; j++) {
a[i][j] += a[i][j - 1] * 10 + str[j] - '0';
//printf("%d -> %d -> %lld\n", i, j, a[i][j]);
}
}
dfs(1, 1, 0, 1);
printf("%lld\n", ans);
}
return 0;
}