题目描述
给出N个数字,不改变它们的相对位置,在中间加入K个乘号和N-K-1个加号,(括号随便加)使最终结果尽量大。因为乘号和加号一共就是N-1个了,所以恰好每两个相邻数字之间都有一个符号。例如:
N=5, K=2,5个数字分别为1、2、3、4、5,可以加成:
12(3+4+5)=24
1*(2+3)*(4+5)=45
(12+3)(4+5)=45
……
输入输出格式
输入格式:
输入文件共有二行,第一行为两个有空格隔开的整数,表示N和K,其中(2<=N<=15, 0<=K<=N-1)。第二行为 N个用空格隔开的数字(每个数字在0到9之间)。
输出格式:
输出文件仅一行包含一个整数,表示要求的最大的结果
最后的结果<=maxlongint
输入输出样例
输入样例#1: 复制
5 2
1 2 3 4 5
输出样例#1: 复制
120
solution
- 很明显的区间dp,状态设计有两种,对应这两种枚举顺序。一种是f[i][j]表示考虑到第i个位置,放了j的乘号的最大值,这个不太好转移
- 那设计状态为f[i][j]表示放了i个乘号考虑到j个位置,转移就是 f [ i ] [ j ] = m a x ( f [ i − 1 ] [ k ] ∗ ( s u m [ j ] − s u m [ k ] ) k < j , j > i f[i][j]=max(f[i-1][k]*(sum[j]-sum[k]) k<j,j>i f[i][j]=max(f[i−1][k]∗(sum[j]−sum[k])k<j,j>i
- 初始值就让 f [ 0 ] [ i ] = s u m [ i ] f[0][i]=sum[i] f[0][i]=sum[i]就可以了
code
const int N=20;
int a[N],sum[N];
int f[N][N];
int main()
{
int n,k;
n=read();k=read();
for(int i=1;i<=n;i++)
{
a[i]=read();
sum[i]=sum[i-1]+a[i];
f[0][i]=sum[i];
}
for(int i=1;i<=k;i++)
{
for(int j=i+1;j<=n;j++)
{
for(int z=i;z<j;z++)
{
f[i][j]=max(f[i][j],f[i-1][z]*(sum[j]-sum[z]));
}
}
}
cout<<f[k][n]<<endl;
return 0;
}