跳到主要内容

1359. Pickup Deliveries

Count All Valid Pickup and Delivery Options

又是一道非常适合Bottom Up的动态规划题

552号题更简单些 起码我是这么觉得

Base Case

当只有一个订单时 只有一种方案

先取(P)后送(D) 组合数便是1

长得这样子:(P1,D1)(P_1, D_1)

观察往上爬的路线🧗

1. P2P_2D2D_2如何配置

PiP_i永远要在DiD_i的左边 这是题目的要求

因此我们先来留意P2P_2该摆哪儿

(P1,D1)(P_1, D_1)这样的组合 有三个槽位(Slots)可安插P2P_2

放进P2P_2后 自然形成四个槽位 但这四个槽位

P2P_2的视角来说 是有变化滴

I. 放在P1P_1左:1 + 3 的格式

++号左 是指 P2P_2左边 的槽位数

++号右 是指 P2P_2右边 的槽位数

II. 放在P1P_1D1D_1中:2 + 2 的格式

III. 放在D1D_1右:3 + 1 的格式

刚才提到PiP_i永远要在DiD_i的左边

因此P2P_2确定位置后 D2D_2永远只能选

上述那些+号右边的槽位

总共有1+2+3=61 + 2 + 3 = 6种可选

于是两份订单数量时 组合数便是1×6=61 \times 6 = 6

2. 由此想像一下PjP_jDjD_j2j2 \leq j

PjP_jDjD_j即将入队时 前面肯定有j1j - 1份订单

形成了总长为2j22j - 2的序列

PjP_j的插入位置于是有2j12j - 1个槽位

这些槽位由左到右 给予DjD_j的合法槽位数

依序是2j1,...,12j - 1, ..., 1个这么多

这不就是等差级数和(2j1)j(2j - 1)j

恰好是在PjP_jDjD_j的安排上

会让截至上一轮的组合数Cj1C_{j - 1} 放大的倍率

于是我们的状态转移方程有的是

Cj=Cj1×j(2j1)    jN;2jC_j = C_{j - 1} \times j(2j - 1) \; \forall \; j \in N; 2 \leq j

好啦~~可直接进入手刻代码环节啰🧑🏻‍💻👩🏻‍💻

老话一句 数字可能来到天文级 记得要取模哦

#include <cmath>
using namespace std;

int countValidSequences(int totalOrders) // LeetCode Q.1359.
{
long long modulo = pow(10, 9) + 7; // Long long prevents overflow.

// Base case when n is 1: pickup 1 followed by delivery 1.
long long validSequences = 1;

for (int prevOrderNum = 1; prevOrderNum <= totalOrders - 1; prevOrderNum++) {
int spotsCount = 2 * prevOrderNum + 1;

// Sum from 1 to spots count.
int multiple = spotsCount * (spotsCount + 1) / 2;

validSequences *= multiple;
validSequences %= modulo;
}

return validSequences;
}

Bottom Up_Efficiency 时间O(n)O(n) 空间O(1)O(1) 状态转移方程也要练习手写呀