首页 > 试题广场 >

小苯的序列分割1.0

[编程题]小苯的序列分割1.0
  • 热度指数:422 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
小苯有一个长度为 n 的序列 a,他希望你能将 a 划分为恰好 m 个非空的连续段,并将其中每一段中的数字求和,组成一个长度恰好 m 的新序列 b。接着,最大化以下式子:

b_1+b_2 \times 2 + b_3 + b_4 \times 2...
即:b 中奇数位置的数字之和,加上偶数位置的数字之和 \times 2

请你帮他算算这个最大值是多少吧。

输入描述:
本题有多组测试数据。
输入的第一行包含一个正整数 T\ (1 \leq T \leq 100),表示数据组数。
接下来包含 T 组数据,每组数据的格式如下:
第一行两个正整数 n,m\ (1 \leq m \leq n \leq 3000),表示小苯的序列 a 的长度,以及需要恰好划分成的连续段个数。
第二行 n 个整数 a_i\ (-10^9 \leq a_i \leq 10^9),表示序列 a
(保证同一个测试文件的所有测试数据中,n 的总和不超过 3000。)


输出描述:
对于每组测试数据:
输出一行一个整数,表示所求式子的最大值。
示例1

输入

2
5 4
1 3 2 4 3
5 1
1 3 2 4 -3

输出

23
7

说明

对于第一组测试数据,划分为:

[1,1], [2,2], [3,3], [4,5] 这四个区间最优,b=\{1,3,2,7\},最大和为:1+3 \times 2 + 2 + 7 \times 2=23
import sys

T=int(input())
for t in range(T):
    n,m=list(map(int,input().strip().split()))
    a=list(map(int,input().strip().split()))
    if n==1 and m==1:
        print(a[0])
    else:
       
        dp=[[-float("inf")]*(1+m) for _ in range(1+n)]
        dp[0][0]=0
        presum=[0]*(n+1)
        for i in range(n):
            presum[i+1]=presum[i]+a[i]

        
        for i in range(1,n+1):
            
            for j in range(1,m+1):
                weight=1 if j%2 else 2
                best=-float("inf")
                for k in range(i):
                    best=max(best,dp[k][j-1]+(presum[i]-presum[k])*weight)
                dp[i][j]=best
        print(dp[n][m])




超时了
发表于 2025-09-09 16:27:23 回复(1)
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int T = sc.nextInt();
        while (T-- > 0) {
            int n = sc.nextInt();
            int m = sc.nextInt();
            long[] a = new long[n + 1];
            for (int i = 1; i <= n; i++) {
                a[i] = sc.nextLong();
            }

            // 前缀和
            long[] prefix = new long[n + 1];
            for (int i = 1; i <= n; i++) {
                prefix[i] = prefix[i - 1] + a[i];
            }

            // dp[i][j] 表示前 i 个数划分为 j 段的最大值
            long[][] dp = new long[n + 1][m + 1];
            for (int i = 0; i <= n; i++) {
                Arrays.fill(dp[i], Long.MIN_VALUE / 2);
            }
            dp[0][0] = 0;

            // 动态规划
            for (int j = 1; j <= m; j++) {
                int weight = (j % 2 == 1 ? 1 : 2);

                // best[k] = max(dp[k][j-1] - prefix[k]*weight)
                long best = Long.MIN_VALUE / 2;

                for (int i = 1; i <= n; i++) {
                    // 先更新 best (相当于枚举k=i-1)
                    best = Math.max(best, dp[i - 1][j - 1] - prefix[i - 1] * weight);

                    // 再利用 best 转移到 dp[i][j]
                    dp[i][j] = prefix[i] * weight + best;
                }
            }

            System.out.println(dp[n][m]);
        }
    }
}

发表于 2025-09-03 09:59:19 回复(0)