1275:【例9.19】乘积最大

题目链接

题意简述

设有一个长度为N的数字串,要求选手使用K个乘号将它分成K+1个部分,找出一种分法,使得这K+1个部分的乘积最大。

同时,为了帮助选手能够正确理解题意,主持人还举了如下的一个例子:

有一个数字串:312, 当N=3,K=1时会有以下两种分法:

  • 3*12=36

  • 31*2=62

这时,符合题目要求的结果是:31*2=62。

现在,请你帮助你的好朋友XZ设计一个程序,求得正确的答案。

样例

点击查看样例

分析

本题探讨的是一个序列在区间上的性质,因此用区间DP
最外层枚举用的乘号的个数
\(dp[i][k]\)表示前\(i\)个数字中使用\(k\)个乘号
然后求前\(k+1,k+2,...,n\)的序列用\(k\)个乘号所能得到的最大值
其中对于前 \(i\) 个字符的序列,用 \(m\) 个乘号相乘时,只需先列出来前 \(m,m+1,...,i-1\) (记为\(j\) ) 个字符的序列用 \(m-1\) 个乘号的最大值,然后第 \(m\) 个乘号的位置就是在第 \(j\) 个字符后.
其最大值的求法是先得到前\(m,m+1,...,i-1\)个字符用\(m-1\)个乘号的最大值 \(dp[j][m-1]\) ,然后乘以 \(a[j+1][i]\) . 取\(max\) 即可.
\(dp[i][k]=max(dp[i][k],dp[j][k-1]*num[j+1][i])\)

预处理:
\(a[i...j]\)表示了\(str[i...j]\)组成的数字
\(dp[i][0]\)即前i个字符用\(0\)个乘号得到的结果,自然是\(a[1][i]\)

代码

点击查看代码
#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=20;
LL a[N][N];
LL dp[N][N];
char s[N];
int main()
{
	//freopen("uva.txt","r",stdin);
	int n,k;
	scanf("%d%d",&n,&k);
	scanf("%s",s+1);
	for(int i = 1;i <= n;i++)
	{
		a[i][i] = s[i]-'0';
	}
	for(int i = 1;i <= n;i++)
	{
		LL t = a[i][i];
		for(int j = i+1;j<=n;j++)
		{
			a[i][j] = t*10 + a[j][j];
			t = a[i][j];
		//	printf("%d %d %lld\n",i,j,a[i][j]);
		}
	}
	for(int i = 1;i <= n;i++)dp[i][0] = a[1][i];
	
	for(int m = 1;m <= k ;m ++)
	{
		for(int i = m + 1;i <= n ;i++)
		{
			for(int j = m ;j < i ;j++)
			{
				dp[i][m] = max(dp[i][m],dp[j][m-1]*a[j+1][i]); 
			}
		}
	}
	printf("%lld\n",dp[n][k]);
	return 0;
}

posted @ 2022-10-10 09:15  LZH_03  阅读(357)  评论(0编辑  收藏  举报