1 条题解

  • 0
    @ 2026-1-27 21:54:32
    #include<bits/stdc++.h>
    using namespace std;
    
    // [1] arr数组-存储每堆石子的数量(下标1~n);brr数组-前缀和数组,brr[i]表示前i堆石子的总数
    int arr[110],brr[110]={};
    // [2] dp[l][r]-合并区间[l, r]内的石子能得到的最小得分;dp_max[l][r]-合并区间[l, r]内的石子能得到的最大得分
    int dp[110][110];
    int dp_max[110][110];
    
    int main(){
        int n;
        cin>>n;  // [3] 读取石子堆数n
        for(int i=1;i<=n;i++){
            cin>>arr[i];
            brr[i]=brr[i-1]+arr[i];  // [4] 计算前缀和:前i堆石子的总数 = 前i-1堆的和 + 当前堆的数量
        }
    
        // 数组初始化
        memset(dp, 0x3f, sizeof(dp));  // [5] 最小得分dp初始化为极大值(0x3f表示不可达,后续取最小值)
        memset(dp_max, 0, sizeof(dp_max));  // [6] 最大得分dp_max初始化为0
        // 单堆石子无需合并,得分是0
        for (int i = 1; i <= n; i++){
            dp[i][i] = 0; 
            dp_max[i][i] = 0;
        }
    
        // 区间DP核心循环:按区间长度从小到大计算(len为区间长度,从2到n)
        for(int len=2;len<=n;len++){
            // 遍历所有长度为len的区间的左端点l
            for(int l=1;l+len-1<=n;l++){
                int r=l+len-1;  // [7] 计算当前区间的右端点r
                
                // 枚举分割点i,将区间[l, r]分为[l, i]和[i+1, r]两个子区间
                for(int i=l;i<r;i++){
                    // 计算当前区间的石子总数(合并时的得分贡献)
                    int sum = brr[r] - brr[l-1];
                    // 状态转移:合并区间[l, r]的得分 = 合并左子区间的得分 + 合并右子区间的得分 + 当前区间的石子总数
                    // 最小得分取所有分割方式中的最小值
                    dp[l][r] = min(dp[l][r], dp[l][i] + dp[i+1][r] + sum);
                    // 最大得分取所有分割方式中的最大值
                    dp_max[l][r] = max(dp_max[l][r], dp_max[l][i] + dp_max[i+1][r] + sum);
                } 
            }
        }
        // 输出合并所有石子(区间[1, n])的最小得分和最大得分
        cout<<dp[1][n]<<endl<<dp_max[1][n];
        return 0;
    }
    
    • 1

    信息

    ID
    1347
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者