> Description
给出长度为n的一串数字串,要求从中插入k个乘号“*”,算出最大的乘积(0可以作为最高位)。
> Input
第一行输入n与k(6≤N≤40,1≤K≤6)。
第二行输入长度为n的数字串。
> Output
输出最大乘积(一个整数)。
> Sample Input
4 2
1231
> Sample Output
62
> 解题思路
这题输入的数字串中间没有空格隔开,所以只能用字符输入(其实我也不知道,反正我是这样做的),输入时还需处理一下。
f[i][j]表示前i个数字插入j个符号的最大乘积,然后就开始循环插入的符号数t、边界j、与划分k,可以发现:
例如 f[5][3]=max(f[2][1]*s[3][5],f[3][1]*s[4][5],f[4][1]*s[5][5])
也就是前k个数字看做一个整体,用符号数-1个乘号,然后再加上一个乘号,与剩下组成的数相乘,比较算出最大值。
状态转移方程:
f[j][t]=max(f[j][t],f[k][t-1]*s[k+1][j])
感性理解一下
(然后在洛谷上面测用这个方法不开longlong20分,开longlong60分)
> 代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
long long f[41][7]={0},ss[41][41];
int n,kk,s[41];
char a;
long long ooo(int x,int y)
{
if(ss[x][y]!=0) return ss[x][y];
for(int i=x;i<=y;i++)
ss[x][y]=ss[x][y]*10+s[i];
return ss[x][y];
}//算出剩下的数字组成的数值
int main()
{
scanf("%d%d\n",&n,&kk);
for(int i=1;i<=n;i++)
{
scanf("%c",&a);
s[i]=a-'0';//s存各个位的数字
f[i][0]=f[i-1][0]*10+s[i];//赋初值:前i个数用0个乘号(=s[1][i])
}
for(int t=1;t<=kk;t++)//循环用t个乘号
for(int j=t+1;j<=n;j++)//循环前j个数;
//t+1:用t个乘号至少有t+1个数
for(int k=t;k<j;k++)//划分界线
f[j][t]=max(f[j][t],f[k][t-1]*ooo(k+1,j));
printf("%lld",f[n][kk]);
return 0;
}