乘号加号
“”
题解:
显然,这道题类似区间dp又不大一样,限制了乘法计算的数量,所以我们采用分段dp,我们用dp[i][j]表示对前i个元素进行j次乘法的最大值并求出元素的前缀和方便计算
代码:
#include<bits/stdc++.h>
using namespace std;
int n,a[105],dp[105][105],sum[105],m;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
dp[i][0]=sum[i];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=min(i-1,m);j++)
for(int k=1;k<=i;k++) dp[i][j]=max(dp[i][j],dp[k][j-1]*(sum[i]-sum[k]));
}
printf("%d",dp[n][m]);
return 0;
}
“知识是第一位的”——by New_Traveller
亿点点小问题
当遇到零的时候,这个算法就会变得很难受,因为这个算法是建立在
a+b*c<(a+b)*c
这个数学公式基础上的
但是
这个式子成立的基础是c>=1且a>0
所以当c==0时,便要想个其他方法
那么
之前我们说道这题有一点区间dp的意思,因为加括号并用乘法合并正好符合区间dp的性质,只是有一点限制,那就是区间的个数有限 怎么办?我们观察到这题的数据规模很小,那不妨再个dp的数组再加一个维度,变成这样:fi,j,p表示区间[i,j]中分成p个块时,区间[i,j]在合并后的最大值!
递推部分便会变成这个亚子:
for(p=1;p<=m;p++) //枚举区间内的括号块的个数
for(r=p+1;r<=n;r++) //枚举区间的宽度
for(i=1;i+r-1<=n;i++){ //枚举左端点
j=i+r-1; //求出右端点
for(k=i;k<j;k++) //枚举区间dp中间点
for(q=0;q<k-i+1&&q<p&&p-q-1<j-k;q++){//这一个循环其实我认为有点问题,下文会说
//枚举左侧区间中括号块的个数
f[i][j][p]=max(f[i][j][p],f[i][k][q]*f[k+1][j][p-q-1]);
if(p-q<j-k) f[i][j][p]=max(f[i][j][p],f[i][k][q]+f[k+1][j][p-q]);
}
}
但是问题又来了:万一右区间长度小于括号块数量怎么办,所以就要再进行一点点改动:
for(p=1;p<=m;p++)
for(r=p+1;r<=n;r++)
for(i=1;i+r-1<=n;i++){
j=i+r-1;
for(k=i;k<j;k++)
for(q=max(p-(j-k),0);q<=min(k-i,p);q++){ //就是这一行和之前的程序不一样
f[i][j][p]=max(f[i][j][p],f[i][k][q]*f[k+1][j][p-q-1]);
if(p-q<j-k) f[i][j][p]=max(f[i][j][p],f[i][k][q]+f[k+1][j][p-q]);
}
}
总结一下就是这样:
#include<bits/stdc++.h>
using namespace std;
#define MAXN 51
typedef long long int lli;
lli f[MAXN][MAXN][MAXN];
int nums[MAXN],sum[MAXN];
int i,j,k,m,n,r,t,p,q;
int main(){
#ifndef ONLINE_JUDGE
freopen("bigexp.in","r",stdin);
freopen("bigexp.out","w",stdout);
#endif
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++) {
scanf("%d",nums+i);
}
sum[0]=0;
for(i=1;i<=n;i++) sum[i]=sum[i-1]+nums[i];
for(i=1;i<=n;i++)
for(j=i;j<=n;j++) f[i][j][0]=sum[j]-sum[i-1];
for(p=1;p<=m;p++)
for(r=p+1;r<=n;r++)
for(i=1;i+r-1<=n;i++){
j=i+r-1;
for(k=i;k<j;k++)
for(q=max(p-(j-k),0);q<=min(k-i,p);q++){
f[i][j][p]=max(f[i][j][p],f[i][k][q]*f[k+1][j][p-q-1]);
if(p-q<j-k) f[i][j][p]=max(f[i][j][p],f[i][k][q]+f[k+1][j][p-q]);
}
}
printf("%lld\n",f[1][n][m]);
return 0;
}
这样,这个完全不像黄题的题就解决了(完结撒花)