最小乘法 DP
题目大意
如果在一个正整数中间插入一些乘号,会得到一个更小的数字。 一个数字有不同的插入方法,会得到不同的数字,我们想知道最大的那个数字是多少?
例如 233 得到 69,,1111 得到 121
思路分析
拿到题目会发现这道题和矩阵链相乘非常相似,以至于我上来就按照矩阵链乘法那样设定状态(啊啊啊思维定式了),即dp[i][j]代表从i到j添加乘号最大的值,仔细一想发现这个状态很有问题,首先并不知道[i,j]这个区间内应该加入多少个乘号,再者这样的状态转移方程也不知道怎么去写。。。
其实这道题状态的设定应该是dp[i][j],i代表前i个数,j代表几个乘号,这么设计状态后便可以发现dp[i][j]的最大值是由dp[i-k][j-1]*最后k个数得到的,只要遍历一边dp[i-k][j-1]的最大值就可以了.
代码
LL cal(int from, int to) {
LL x = 0;
for(int i = from; i <= to; ++i) {
x = x * 10 + (a[i] - '0');
}
return x;
}
int main() {
while(~scanf("%d", &n)) {
memset(dp, 0, sizeof(dp));
scanf("%s", a);
int len = strlen(a);
if(n == 0) {
printf("%lld\n", cal(0, len - 1));
continue;
}
for(int i=1;i<=len;++i)
dp[i][0]=cal(0,i-1);//初始化
for(int i = 1; i <= len; ++i) {
for(int j = 1; j <= n; ++j) {
if(i > j) {
for(int k = 1; k <= i - j; ++k) {
dp[i][j] = max(dp[i][j], dp[i - k][j - 1] * cal(i - k, i - 1));
}
}
}
}
printf("%lld\n", dp[len][n]);
}
return 0;
}
总结
DP是真的难嗷
这道dp其实并不是很难,难点主要就在找状态上(我裂开来),另外dp过程中的初始化base条件还不够熟练,经常算出来个0不知道错在哪儿(我再次裂开)