题解 AT2370 【[AGC013D] Piling Up】
在博客园食用更佳:https://www.cnblogs.com/PinkRabbit/p/AGC013.html。
我们假设初始时红砖的数量为
同时,我们记第
观察第
- 操作
RR
:先拿出一块红砖,然后塞入一红一蓝两砖,再拿出一块红砖。
此操作仅能在x_i > 0 时被执行,并且x_{i + 1} = x_i - 1 (\boldsymbol{x} 减少\boldsymbol{1} )。 - 操作
RB
:先拿出一块红砖,然后塞入一红一蓝两砖,再拿出一块蓝砖。
此操作仅能在x_i > 0 时被执行,并且x_{i + 1} = x_i (不变)。 - 操作
BR
:先拿出一块蓝砖,然后塞入一红一蓝两砖,再拿出一块红砖。
此操作仅能在x_i < N 时被执行,并且x_{i + 1} = x_i (不变)。 - 操作
BB
:先拿出一块蓝砖,然后塞入一红一蓝两砖,再拿出一块蓝砖。
此操作仅能在x_i < N 时被执行,并且x_{i + 1} = x_i + 1 (\boldsymbol{x} 增加\boldsymbol{1} )。
对于一种操作序列,根据上面的
我们考虑直接进行 DP:令
错误!这样计算会使得一个合法的操作序列被统计多次,也就是上面的
我们不妨考虑必须在
体现在 DP 过程中,即是存在一个时刻 RB
操作。
所以我们更换状态定义,令
同时定义
转移仍然显然,答案即为
#include <cstdio>
typedef long long LL;
const int Mod = 1000000007;
const int MN = 3005;
int N, M;
int f[2][MN], g[2][MN], Ans;
int main() {
scanf("%d%d", &N, &M);
int o = 0;
for (int i = 1; i <= N; ++i) f[o][i] = 1;
g[o][0] = 1;
for (int i = 1; i <= M; ++i) {
o ^= 1;
for (int j = 0; j <= N; ++j) f[o][j] = g[o][j] = 0;
for (int j = 0; j <= N; ++j) {
if (j) {
f[o][j] = (f[o][j] + f[o ^ 1][j - 1]) % Mod;
g[o][j] = ((LL)g[o][j] + g[o ^ 1][j - 1] + g[o ^ 1][j]) % Mod;
if (j == 1) g[o][j] = (g[o][j] + f[o ^ 1][j]) % Mod;
else f[o][j] = (f[o][j] + f[o ^ 1][j]) % Mod;
}
if (j < N) {
g[o][j] = ((LL)g[o][j] + g[o ^ 1][j + 1] + g[o ^ 1][j]) % Mod;
if (!j) g[o][j] = (g[o][j] + f[o ^ 1][j + 1]) % Mod;
else f[o][j] = ((LL)f[o][j] + f[o ^ 1][j + 1] + f[o ^ 1][j]) % Mod;
}
}
}
for (int j = 0; j <= N; ++j) Ans = (Ans + g[o][j]) % Mod;
printf("%d\n", Ans);
return 0;
}