Luogu-P9743-旅行
题目 P9743 「KDOI-06-J」旅行
题目描述
小 C 在 C 国旅行。
C 国有 $n\times m$ 个城市,可以看做 $n\times m$ 的网格。定义 $(i,j)$ 表示在网格中第 $i$ 行第 $j$ 列的城市。
该国有 $2$ 种交通系统:
- 对于所有 $1\leq i<n,1\leq j\leq m$,$(i,j)$ 到 $(i+1,j)$ 有一段由 L 公司修的单向铁路;
- 对于所有 $1\leq i\leq n,1\leq j<m$,$(i,j)$ 到 $(i,j+1)$ 有一段由 Z 公司修的单向铁路;
在每一个城市有一个售票口,$(i,j)$ 城市的售票口可以用 $a_{i,j}$ 元购买一张 L 公司的铁路票,$b_{i,j}$ 元购买一张 Z 公司的铁路票。当你拥有一个公司的一张铁路票时,你可以乘坐这个公司的任意一段铁路,并消耗掉这张铁路票。注意,一张铁路票可以且仅可以使用一次。
小 C 原来在城市 $(1,1)$。他想要在 C 国旅游,但是他不想浪费任何的钱(即,当他旅游完毕时手上不应该有多余的车票)。对于所有 $1\leq x\leq n,1\leq y\leq m$,求他花 $k$ 元钱并在城市 $(x,y)$ 结束旅行的方案数,对 $998\ 244\ 353$ 取模。
两种旅行方案不同,当且仅当小 C 经过的城市不同,或他在某一个城市购买的某家公司的铁路票数量不同。
输入格式
从标准输入读入数据。
输入的第一行包含三个正整数 $n,m,k$,表示网格的大小和钱的数目。
接下来 $n$ 行,每行 $m$ 个正整数,第 $i$ 行第 $j$ 个正整数表示 $a_{i,j}$。
接下来 $n$ 行,每行 $m$ 个正整数,第 $i$ 行第 $j$ 个正整数表示 $b_{i,j}$。
输出格式
输出到标准输出。
输出一共 $n$ 行,每行 $m$ 个整数,表示到每个点钱恰好花完并结束旅行的方案数,对 $998\ 244\ 353$ 取模。
思路:dp
dp表
注意到本题对于一格共有 $5$ 个变量:
- 横坐标 $x$
- 纵坐标 $y$
- 横着走的车票数 $sx$
- 竖着走的车票数 $sy$
- 剩余钱数 $money$
并且根据本题的数据范围,考虑五维的dp表 $dp[x][y][sx][sy][money]$。
状态
初状态:由于初始位置是 $(1,1)$,此时两种车票都没有,剩余钱数为题中的 $k$,因此以下方程恒成立。
1
dp[1][1][0][0][k] = 1;
状态转移方程:$dp[x][y][sx][sy][money]$ 为所有能变化成这种状态的方案数总和。
而根据题意,存在以下状态可以变成 $dp[x][y][sx][sy][money]$:
- 从 $(x-1, y)$,花费一张横向车票。$\rightarrow dp[x-1][y][sx+1][sy][money]$
- 从 $(x, y-1)$,花费一张纵向车票。$\rightarrow dp[x][y-1][sx][sy+1][money]$
- 原地花 $a[x][y]$ 的钱买一张横向车票。$\rightarrow dp[x][y][sx-1][sy][money+a[x][y]]$
- 原地花 $b[x][y]$ 的钱买一张纵向车票。$\rightarrow dp[x][y][sx][sy-1][money+b[x][y]]$
因此,$dp[x][y][sx][sy][money]$ 应为以上四个式子的和(注意取模)。
1
2
3
4
5dp[x][y][sx][sy][money] +=
dp[x - 1][y][sx + 1][sy][money] +
dp[x][y - 1][sx][sy + 1][money] +
dp[x][y][sx - 1][sy][money + a[x][y]] +
dp[x][y][sx][sy - 1][money + b[x][y]];需要注意,以上方程并不正确。
因为根据题意,购买车票的顺序不同是不算方案不同的,例:先买 $1$ 横向再买 $1$ 纵向,和先买 $1$ 纵向再买 $1$ 横向不应算两种方案。
因此,还应该在同时买两种车票($sx \neq 0 $且$ sy \neq 0$)时,去除重复部分 $dp[i][y][sx-1][sy-1][money+a[x][y]+b[x][y]]$。
末状态:题目要求到达的点不能有票($sx=sy=0$)和剩下的钱($money=0$),因此到达 $(x,y)$ 的方案数为:
1
dp[x][y][0][0][0];
遍历的范围
- $x$ 和 $y$ 自然是 $[1,n]$ 和 $[1,m]$
- $sx$ 可以这样考虑:当横坐标为 $x$ 时,最多可拥有 $n-x$ 张横向的票,因为再多也用不上了。
所以 $sx$ 的范围是 $[0,n-x]$。$sy$ 同理:$[0,m-y]$。 - $money$ 比较特殊。虽然范围很容易想到是 $[0,k]$,但是方程中是由较大的钱数计算较小的钱数,所以要倒序循环。
空间压缩:滚动数组
此时,虽然看起来十分完美,但是数组太大了,会MLE。
注意到:当横坐标为 $x$ 时的方案数只与 $x$ 和 $x-1$ 有关,所以使用滚动数组方法将第一维压缩成 $2$ 而不是 $n$。
方法
使用一个变量 $i$ 存储 $x$的奇偶,每次循环将 $i$ 置为 $1 \ \mathrm{xor}\ i$。
压缩后状态
初状态不变。
状态转移方程中所有的 $x$ 换成 $i$,$x-1$ 换成 $1 \ \mathrm{xor} \ i$(另一个数组就是上一个 $x$)。
末状态的处理有一些变化。因为 $dp$ 数组不再存储每个 $(x,y)$ 的方案数,所以应在计算完之后存到另一个数组 $ans$ 里。
AC Code
1 | // template v4 |