背包dp就是选与不选的情况

dp[j] = max(dp[j], dp[j - a[i][k] * 2 - 1] + k*i);//这是一个背包dp题的转移方程

背包问题的题目都有明显的选与不选的情况,大多都能抽象成上面的方程;

区间dp,从小区间推大区间枚举长度从小到大,反之则相反;

 1 int main() {
 2     int n;
 3     cin >> n;
 4     for (int i = 1; i <= n; ++i) {
 5         for (int j = i + 1; j <= n; ++j) {
 6             for (int k = i; k < j; ++k)
 7                 f[i][j] = max(f[i][j], f[i][k] + f[k + 1][j]);
 8         }
 9     }//不要从左到右去枚举区间,应该枚举区间长度
10     return 0;
11 }

正确写法

int main() {
    int n;
    cin >> n;
    for (int i = 1; i <n; ++i) {//i表示区间长度
        for (int j = 1; j +i<= n; ++j) {//j表示左端点
            for (int k = i; k < j+i; ++k)//k表示分割线
                f[j][j+i] = max(f[j][j+i], f[j][k] + f[k + 1][j+i]);
        }
    }
    return 0;
}

对于环的区间问题,把n变成2n在跑就行了

 1 int main() {
 2     int n;
 3     cin >> n;
 4     for (int i = 1; i <= n; ++i) {
 5         cin >> a[i];
 6         a[i + n] = a[i];
 7     }
 8     n *= 2;
 9     for (int i = 1; i <n; ++i) {
10         for (int j = 1; j +i<= n; ++j) {
11             for (int k = i; k < j+i; ++k)
12                 f[j][j+i] = max(f[j][j+i], f[j][k] + f[k + 1][j+i]);
13         }
14     }
15     int ans = 0;
16    n/=2;
16 for (int i = 1; i <= n; ++i) { 17 ans = max(ans, f[i][i + n - 1]);//右区间要减一 18 } 19 return 0; 20 }

难点是分割线的dp方程推导