本题针对于区间进行操作,是一个区间dp的问题。对于某个区间i,j能够得到的最大值等于在区间里面分成两部分中所有两部分的最大值。那么再看分出来的这两部分其实又可以划分两部分。
那么动态规划的状态转移方程就出来了:dp[i][j] = max(dp[i][j], dp[i][k]+dp[k+1][j]+sum[i][j]);。
最后以最短的区间来世初步动态规划边长就行。
至于圈这个特殊性,可以使用加倍的方式来代替,也就是在数列后面接上一个重复的数列,这样转一圈之后回来就可以表示出来了。
#include <bits/stdc++.h> using namespace std; const int maxn = 400+10; int n; //dp[i][j] = max(dp[i][j], dp[i][k]+dp[k+1][j]+sum[i][j]); int dp[maxn][maxn]; int dp_min[maxn][maxn]; int sum[maxn]; int a[maxn]; int main() { cin>>n; memset(dp_min, 0x3f3f3f, sizeof(dp_min)); for (int i=1;i<=n;i++) { cin>>a[i]; // dp[i][i] = a[i]; a[i+n] = a[i]; dp_min[i][i] = 0; dp_min[i+n][i+n] = 0; } for (int i=1;i<=n*2;i++) { sum[i] = sum[i-1]+a[i]; } int ans_max=INT_MIN; int ans_min=INT_MAX; for (int i=2;i<=n;i++) { for (int l=1;l+i-1<=n*2;l++) { int r = l+i-1; for (int k=l;k<=r-1;k++) { dp[l][r] = max(dp[l][r], dp[l][k]+dp[k+1][r]+sum[r]-sum[l-1]); dp_min[l][r] = min(dp_min[l][r], dp_min[l][k]+dp_min[k+1][r]+sum[r]-sum[l-1]); } } } for (int i=1;i+n-1<=n*2;i++) { int r = i+n-1; ans_max = max(ans_max, dp[i][r]); ans_min = min(ans_min, dp_min[i][r]); } cout<<ans_min<<endl; cout<<ans_max<<endl; return 0; }