[tyvj1045]最大的算式
描述
题目很简单,给出N个数字,不改变它们的相对位置,在中间加入K个乘号和N-K-1个加号,(括号随便加)使最终结果尽量大。因为乘号和加号一共就是N-1个了,所以恰好每两个相邻数字之间都有一个符号。例如:
N=5, K=2,5个数字分别为1、2、3、4、5,可以加成:
1*2*(3+4+5)=24
1*(2+3)*(4+5)=45
(1*2+3)*(4+5)=45
……
N=5, K=2,5个数字分别为1、2、3、4、5,可以加成:
1*2*(3+4+5)=24
1*(2+3)*(4+5)=45
(1*2+3)*(4+5)=45
……
输入格式
输入文件共有二行,第一行为两个有空格隔开的整数,表示N和K,其中(2<=N<=15, 0<=K<=N-1)。第二行为 N个用空格隔开的数字(每个数字在0到9之间)。
输出格式
输出文件仅一行包含一个整数,表示要求的最大的结果
最后的结果<=maxlongint
最后的结果<=maxlongint
测试样例1
输入
5 2
1 2 3 4 5
输出
120
备注
对于30%的数据,N<= 10;
对于全部的数据,N <= 100。
对于全部的数据,N <= 100。
分析
由于括号可以随意添加,那么最直接的想法是把一段式子分成左右两段,由这两段递推得解。由于不等式的性质,左右当左右两段取到最大值时合起来一定最优(a>c>0, b>d>0⇒a+b>c+d, a*b>c*d)。
设F(l, r, k)为[l, r]上数字添加k个乘号算得的最大值,则方程:
F(l, r, k) = A[l], l=r;
F(l, r, k) = max{ max{F(l, d, k’) + F(d+1, k-k’)} (l≤d<r, 0≤k’≤k, k’≤d-l, k-k’≤r-d-1), max{F(l, d, k’) + F(d+1, k-k’-1)} (l≤d<r, 0≤k’≤k, k’≤d-l, k-k’≤r-d) }
当然,这样的话枚举乘号个数的时候会比较复杂,可以简化。
设F(i, j)为前i个数添加j个乘号的最大值,则方程:
F(i, j) = max{F(i-1, j), F(k, j-1) * (S[i] - S[k] + A[k])} (0<k<i)
代码
1 #include <iostream> 2 using namespace std; 3 unsigned long long F[102][102]; 4 unsigned long long S[102]; 5 unsigned long long A[102]; 6 int N, K; 7 int main() 8 { 9 cin >> N >> K; 10 for (int i = 1; i <= N; ++i) { 11 cin >> A[i]; 12 S[i] = S[i - 1] + A[i]; 13 } 14 for (int i = 1; i <= N; ++i) { 15 F[i][0] = F[i - 1][0] + A[i]; 16 for (int j = 1; j < i && j <= K; ++j) 17 for (int k = 1; k != i; ++k) 18 if (F[k][j - 1] * (S[i] - S[k]) > F[i][j]) 19 F[i][j] = F[k][j - 1] * (S[i] - S[k]); 20 } 21 cout << F[N][K]; 22 return 0; 23 }