P1880 [NOI1995]石子合并

P1880 [NOI1995]石子合并

做过类似的,不过这题稍微有点不一样:是环不是链。

只要把链复制一遍原来的链的后面,就可以化环为链了。

注意题目求的是N堆石子合并,枚举区间长度的时候依然是从2枚举到N。

int a[maxn];
int b[maxn];
//前缀和
int dp1[maxn][maxn], dp2[maxn][maxn];

int main()
{
    int N; cin >> N;
    memset(dp1, INF, sizeof(dp1));
    memset(dp2, -INF, sizeof(dp2));
    for (int i = 1; i <= N; i++) {
        dp1[i][i] = dp2[i][i] = dp1[N + i][N + i] = dp2[N + i][N + i] = 0;
    }
   //自己和自己合并得分为0
    for (int i = 1; i <= N; i++) {
        cin >> a[i];
        a[i + N] = a[i];
    }
  //化环为链
    for (int i = 1; i <= N + N - 1; i++) {
        b[i] = b[i - 1] + a[i];
    }

    for (int len = 2; len <= N; len++) {
        //枚举长度
        for (int l = 1; l <= N+N - len + 1; l++) {
            //枚举左端点l
            int r = l + len - 1;
            for (int spl = l; spl <= r - 1; spl++) {
                //枚举分割点split
                //表示在spl堆与spl+1堆之间分割
                dp1[l][r] = min(dp1[l][r], dp1[l][spl] + dp1[spl + 1][r]);
                dp2[l][r] = max(dp2[l][r], dp2[l][spl] + dp2[spl + 1][r]);
            }
            dp1[l][r] += b[r] - b[l - 1];
            dp2[l][r] += b[r] - b[l - 1];
        }
    }
    //长度为N的区间全扫一遍取最大/最小值
    int mmax = -1;
    int mmin = INF;
    for (int i = 1; i <= N; i++) {
        mmin = min(mmin, dp1[i][i + N - 1]);
        mmax = max(mmax, dp2[i][i + N - 1]);
    }
    cout << mmin << endl << mmax << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/streamazure/p/13693971.html