线性动态规划入门
线性 DP 是动态规划中最基础且常见的一类问题。其核心特点是状态转移仅依赖于前一个或前几个状态,状态间呈线性关系,通常可用一维或二维数组存储。
我们在入门阶段遇到的《下楼梯》和《数字三角形》本质上都是线性 DP 的变体。下面通过四个经典题目,梳理线性 DP 的核心思路与实现细节。
1. 台阶问题 (P1192)
题目描述
有 n 个台阶,每次可以走 1 到 k 步,求走到第 n 个台阶的方案数。结果需对 100003 取模。
解题思路
这道题是'下楼梯'问题的加强版。我们按照动态规划的常规步骤来分析:
状态定义
dp[i] 表示走到第 i 个台阶的所有方案数。
状态转移
要到达第 i 个台阶,可以从 i-1, i-2, ..., i-k 处跳过来。因此:
dp[i] = sum(dp[i-j]),其中 1 <= j <= k。
由于数据量较大,计算过程中需要随时取模。注意边界检查,当 i-j < 0 时停止累加,避免访问负下标。
初始化
这里有个小技巧:直接将 dp[0] 置为 1。这样从 dp[1] 开始循环时,逻辑自然成立,无需单独处理前 k 个台阶的初始化。
代码实现
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10, MOD = 1e5 + 3;
int n, k;
LL dp[N];
int main() {
cin >> n >> k;
// 初始化:dp[0]=1 代表起点有一种方案(不动)
dp[0] = 1;
// 循环填表
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= k; j++) {
if (i - j < 0) break;
dp[i] = (dp[i] + dp[i - j]) % MOD;
}
}
cout << dp[n] << endl;
;
}


