AT2370 [AGC013D] Piling Up

https://www.luogu.com.cn/problem/AT2370

套路题
设 f [ i ] [ j ] 表 示 进 行 了 i 次 操 作 , 红 球 有 j 个 的 颜 色 序 列 数 设f[i][j]表示进行了i次操作,红球有j个的颜色序列数 f[i][j]ij

转移分 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]ij,

代码实现不难
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;
}
posted @ 2021-10-18 19:12  lahlah  阅读(49)  评论(0编辑  收藏  举报