首先先上大佬DP法的AC代码(原链接)
#include<bits/stdc++.h> using namespace std; int n,m,f1[110][110][110],f2[110][110][110],a[110],sum[110]; int mod(int x){ return (x%10+10)%10; } int main(){ cin>>n>>m; for(int i=1;i<=n;i++){cin>>a[i];sum[i]=sum[i-1]+a[i];} for(int i=1;i<=n;i++){a[i+n]=a[i],sum[i+n]=sum[i]+sum[n];} memset(f2,127,sizeof(f2));//f2记录的是最小值 所以要初始化为极大值 for(int i=1;i<=2*n;i++){ for(int j=i;j<=2*n;j++){ f1[i][j][1]=f2[i][j][1]=mod(sum[j]-sum[i-1]);//预处理每段的值 } } for(int l=1;l<=n;l++){//区间长度 for(int i=1,j=i+l-1;j<=2*n;i++,j++){//左右端点 for(int h=2;h<=m;h++){//段数 for(int k=i+h-1;k<j;k++){//短点 f1[i][j][h]=max(f1[i][j][h],f1[i][k][h-1]*mod(sum[j]-sum[k])); f2[i][j][h]=min(f2[i][j][h],f2[i][k][h-1]*mod(sum[j]-sum[k])); } } } } int maxn=0,minn=0x7fffffff; for(int i=1;i<=n;i++){//找答案啦~~~ maxn=max(maxn,f1[i][i+n-1][m]); minn=min(minn,f2[i][i+n-1][m]); } cout<<minn<<endl<<maxn; }
大佬思路
设状态
DP的套路就是题目问什么就设什么,然后这有是一道区间DP经典题
所以我们设f[i][j][h]表示从i到j分成h段的最大最小值
转移方程
由状态我们可以得出转移方程:
f[i][j][h]=max/min(f[i][j][h],f[i][k][h-1]*sum)f[i][j][h]=max/min(f[i][j][h],f[i][k][h−1]∗sum)
先枚举区间长度
从正常的区间DP模板我们知道应该
为什么呢:
如果我们先枚举i,j
比如说i=1,j=10,k=5时
f[1][5][h]并没有被处理出来这样就错了
再枚举左右端点
这个好理解,区间DP嘛
再是枚举段数
这个也很好理解 要更新答案嘛