AT2370 [AGC013D] Piling Up
https://www.luogu.com.cn/problem/AT2370
套路题
设
f
[
i
]
[
j
]
表
示
进
行
了
i
次
操
作
,
红
球
有
j
个
的
颜
色
序
列
数
设f[i][j]表示进行了i次操作,红球有j个的颜色序列数
设f[i][j]表示进行了i次操作,红球有j个的颜色序列数
转移分 R R , R B , B B , B R RR,RB,BB,BR RR,RB,BB,BR(R:红,B:蓝)四种情况讨论一下转移即可
但是可能会算重复,即便红球个数不同,得到的颜色序列也可能是一样的
借用ez_lcw大佬的blog
上面这几个得到的颜色序列都是一样的,
只用保留最下面那个就行了(即触碰到底端的)
于是改一波状态
设
f
[
i
]
[
j
]
[
0
/
1
]
表
示
进
行
了
i
次
操
作
,
红
球
有
j
个
,
是
否
有
触
碰
到
底
端
的
颜
色
序
列
数
设f[i][j][0/1]表示进行了i次操作,红球有j个,是否有触碰到底端的颜色序列数
设f[i][j][0/1]表示进行了i次操作,红球有j个,是否有触碰到底端的颜色序列数
代码实现不难
code:
#include<bits/stdc++.h>
#define N 3005
#define mod 1000000007
using namespace std;
void add(int &x, int y) { x += y;
if(x >= mod) x -= mod;
}
int n, m, f[N][N][2];
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++) f[0][i][0] = 1;
f[0][0][1] = 1;
for(int i = 0; i < m; i ++) {
for(int j = 0; j <= n; j ++) {
if(j) {
// RR
add(f[i + 1][j - 1][1], f[i][j][1]);
if(j == 1) add(f[i + 1][j - 1][1], f[i][j][0]);
else add(f[i + 1][j - 1][0], f[i][j][0]);
// RB
add(f[i + 1][j][1], f[i][j][1]);
if(j == 1) add(f[i + 1][j][1], f[i][j][0]);
else add(f[i + 1][j][0], f[i][j][0]);
}
if(j < n) {
// BB
add(f[i + 1][j + 1][0], f[i][j][0]);
add(f[i + 1][j + 1][1], f[i][j][1]);
// BR
add(f[i + 1][j][0], f[i][j][0]);
add(f[i + 1][j][1], f[i][j][1]);
}
}
}
int ans = 0;
for(int i = 0; i <= n; i ++) add(ans, f[m][i][1]);
printf("%d", ans);
return 0;
}