暑假集训day1 水题 乘法最大

题目大意:有一个长度为N的字符串,要求用K个乘号将其分成K+1个部分,求各个部分相乘的最大值
输入:第一行输入N和K,第二行输入一个长度为N的字符串

算法分析

  1.  这个题只是一个简单的dp(甚至连区间dp都不是)
  2.  dp[i][j]表示前i个数字里面用了j个乘号,而枚举的状态k表示前k个数字用了j-1个乘号,然后用dp[k][j-1]去和后面的数字相乘
  3.  由2可知我们需要一个数组sum[i][j]表示从i到j的数字(也就这和平时的题不一样了):
          想一下如果说后面3个数字为123那么要乘的便是123,而我们平时的算法前缀和或者直接读取数据并不能表示出从1这个位置到3这个位置表示的一百二十三
          所以我们用sum数组提前处理好
      
          `for(int i = 1;i <= n;++i)
		for(int j = i;j <= n;++j)
			sum[i][j] = sum[i][j-1]*10 + b[j];`
  `

   4.sum数组处理好就是一个简单的dp了,下面是代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int n,m,b[maxn],sum[50][50],dp[50][50];
char a[maxn];

int main(){
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;++i){
		scanf(" %c",&a[i]);
		b[i] = a[i]-'0';
	}
	for(int i = 1;i <= n;++i)
		for(int j = i;j <= n;++j)
			sum[i][j] = sum[i][j-1]*10+b[j];
	dp[0][0] = 1;
	for(int i = 1;i <= n;++i)dp[i][0] = sum[1][i];	
	for(int i = 1;i <= n;++i)
		for(int j = 1;j <= i;++j){
			if(dp[i][i-1] == 0)dp[i][i-1] = 1;
			dp[i][i-1] *= b[j];
		}
	dp[1][0] = b[1];
	for(int i = 2;i <= n;++i)
		for(int j = 1;j < i && j <= m;++j)
			for(int k = j;k < i;++k)
				dp[i][j] = max(dp[i][j],dp[k][j-1]*sum[k+1][i]);
	printf("
%d
",dp[n][m]);
	return 0;
}
原文地址:https://www.cnblogs.com/2004-08-20/p/13184457.html