题解:学而思编程 数列划分

【题目来源】

学而思编程:数列划分

【题目描述】

给出 \(n\) 项的数列,要求将数列划分成若干段,且每一段之和都不超过 \(s\)。求一共有多少种满足要求的划分方法。

方法数很大,只要求输出除以 \(10^9\) 的余数。

【输入】

\(1\) 行,两个正整数 \(n,s\)

\(2\) 行,\(n\) 个正整数 \(a_1,a_2,⋯ ,a_n\)

【输出】

一个整数,划分方法数除以 \(10^9\) 的余数。

【输入样例】

5 3
1 2 1 1 1

【输出样例】

10

【核心思想】

  1. 问题分析:给定长度为 \(n\) 的数列 \(a_1, a_2, \ldots, a_n\),需要将其划分为若干连续段,使得每段的和都不超过 \(s\)。求满足条件的划分方法总数,结果对 \(10^9\) 取模。这是一个线性动态规划问题,需要枚举最后一段的起始位置。

  2. 算法选择

    • 动态规划(DP)\(dp[i]\) 表示前 \(i\) 个元素的划分方案数
    • 前缀和优化\(sa[i]\) 表示前 \(i\) 个元素的前缀和,用于 \(O(1)\) 计算区间和
  3. 关键步骤

    • 计算前缀和数组 \(sa[i] = sa[i-1] + a[i]\),用于快速查询区间和
    • 初始化\(dp[0] = 1\)(空数组有 \(1\) 种划分方式)
    • 状态转移(从 \(i = 1\)\(n\)):
      • 枚举最后一段的起始位置 \(j\)(从 \(i\) 向前遍历到 \(1\)
      • 检查区间 \([j, i]\) 的和是否 \(\leq s\)\(sa[i] - sa[j-1] \leq s\)
      • 若满足条件:\(dp[i] = (dp[i] + dp[j-1]) \mod MOD\)
        • \(dp[j-1]\) 表示前 \(j-1\) 个元素的划分方案数
        • 将最后一段 \([j, i]\) 接在这些方案后面,形成新的划分
    • 输出 \(dp[n]\) 作为答案
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n^2)\),外层遍历 \(i\),内层遍历 \(j\),每次区间和查询 \(O(1)\)
    • 空间复杂度:\(O(n)\),存储 \(dp\) 数组和前缀和数组 \(sa\)
  5. 线性DP与区间划分的核心思想

    • 最优子结构:前 \(i\) 个元素的划分方案只与前面位置的方案有关
    • 枚举最后一段:通过枚举最后一段的起始位置 \(j\),将问题分解为子问题
    • 前缀和优化:将区间和计算从 \(O(n)\) 优化到 \(O(1)\)
    • 取模运算:方案数可能很大,每次加法后取模防止溢出
    • 适用于序列划分、字符串分割、区间DP等场景

【算法标签】

线性DP-一维

【代码详解】

#include<iostream>
#include<algorithm>
using namespace std;

const int MOD = 1e9;  // 模数
int n, s, a[1005], sa[1005], dp[1005];  // n: 数字个数,s: 最大和限制,a: 原数组,sa: 前缀和数组,dp: 动态规划数组

int main()
{
    cin >> n >> s;  // 读入n和s
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];  // 读入第i个数字
        sa[i] = sa[i - 1] + a[i];  // 计算前缀和
    }

    dp[0] = 1;  // 空子数组有1种划分方式

    for (int i = 1; i <= n; i++)  // 遍历每个位置
    {
        for (int j = i; j >= 1; j--)  // 向前遍历可能的划分点
        {
            // 检查从j到i的子数组和是否不超过s
            if (sa[i] - sa[j - 1] <= s)
            {
                // 如果满足条件,将dp[j-1]的方案数加到dp[i]上
                dp[i] = (dp[i] + dp[j - 1]) % MOD;
            }
        }
    }

    cout << dp[n];  // 输出前n个元素的划分方案总数
    return 0;
}

【运行结果】

5 3
1 2 1 1 1
10
posted @ 2026-06-14 10:46  团爸讲算法  阅读(11)  评论(0)    收藏  举报