动态规划之线性DP-安全序列

问题描述

小蓝是工厂里的安全工程师,他负责安放工厂里的危险品。

工厂是一条直线,直线上有 n 个空位,小蓝需要将若干个油桶放置在 n 个空位上,每 2 个油桶中间至少需要 k 个空位隔开,现在小蓝想知道有多少种放置油桶的方案,你可以编写一个程序帮助他吗?

由于这个结果很大,你的输出结果需要对  取模。

输入格式

第一行包含两个正整数n,k,分别表示 n 个空位与 k 个隔开的空位。

输出格式

输出共 1行,包含 1 个整数,表示放置的方案数对  取模。

样例输入

4 2

样例输出

6

说明

用 0代表不放,1 代表放,6 种情况分别为:

000010000100001000011001

评测数据规模

对于所有评测数据,

思路:

当放一个油桶时,每一个空位都有一个可能

当放两个油桶时,则前 k 个空位不能放油桶,最多在第 i-k-1 个位置才能放油桶,方案数等于 dp[i-k-1]

解题代码:

#include 
using namespace std;
typedef long long ll;
const ll N=1e6+10,p=1e9+7;

ll dp[N],prefix[N];
int main()
{
  int n,k;cin>>n>>k;
  dp[0]=prefix[0]=1;
  for(int i=1;i<=n;i++)
  {
    if(i-k-1<1)dp[i]=1;
    else dp[i]=prefix[i-k-1];
    prefix[i]=(prefix[i-1]+dp[i])%p;
  }
  cout<

1、动态规划定义

  • dp[i]:表示前 i 个空位的放置方案数。

  • prefix[i]:表示前 i 个空位的前缀和,即 prefix[i] = dp[0] + dp[1] + ... + dp[i]

 2、动态规划转移方程

  • 对于第 i 个空位:

    • 如果选择不放油桶,则方案数等于 dp[i-1]

    • 如果选择放油桶,则前 k 个空位不能放油桶,方案数等于 dp[i-k-1]

  • 因此,动态规划转移方程为:

    dp[i] = dp[i-1] + dp[i-k-1]

    其中:

    • dp[i-1]:不放油桶的方案数。

    • dp[i-k-1]:放油桶的方案数。

3、前缀和的作用

  • 前缀和 prefix[i] 用于快速计算 dp[i]

  • 由于 dp[i] 依赖于 dp[i-1] 和 dp[i-k-1],而 dp[i-1] 可以通过 prefix[i-1] - prefix[i-2] 计算,dp[i-k-1] 可以直接通过 prefix[i-k-1] 计算。

  • 使用前缀和可以将动态规划的转移优化为 O(1) 的时间复杂度。

4、示例分析

假设输入:

n = 4, k = 2
(1) 初始化
  • dp[0] = prefix[0] = 1

(2) 动态规划转移
  • i = 1

    • i - k - 1 = 1 - 2 - 1 = -2 < 1,所以 dp[1] = 1

    • prefix[1] = (prefix[0] + dp[1]) % p = (1 + 1) % p = 2

  • i = 2

    • i - k - 1 = 2 - 2 - 1 = -1 < 1,所以 dp[2] = 1

    • prefix[2] = (prefix[1] + dp[2]) % p = (2 + 1) % p = 3

  • i = 3

    • i - k - 1 = 3 - 2 - 1 = 0 < 1,所以 dp[3] = 1

    • prefix[3] = (prefix[2] + dp[3]) % p = (3 + 1) % p = 4

  • i = 4

    • i - k - 1 = 4 - 2 - 1 = 1 >= 1,所以 dp[4] = prefix[1] = 2

    • prefix[4] = (prefix[3] + dp[4]) % p = (4 + 2) % p = 6

(3) 结果
  • prefix[4] = 6,表示有 6 种放置方案。

5、为什么返回 prefix[n]

  • prefix[n] 表示前 n 个空位的总方案数。

  • 因为 dp[i] 只表示前 i 个空位的方案数,而 prefix[i] 是 dp[0] 到 dp[i] 的累加和。

  • 最终答案需要包括所有可能的方案数,因此返回 prefix[n]

6、动态规划的过程总结

  1. 定义状态dp[i] 表示前 i 个空位的放置方案数。

  2. 转移方程dp[i] = dp[i-1] + dp[i-k-1]

  3. 前缀和优化:使用 prefix[i] 快速计算 dp[i]

  4. 初始化dp[0] = prefix[0] = 1

  5. 结果:返回 prefix[n],表示前 n 个空位的总方案数。

你可能感兴趣的:(动态规划,算法)