題面
題解
將每一輪操作之後的狀態看作一條折線,其中橫座標是第\(i\)輪操作,縱座標是剩餘黑球的個數。
那麼構建一條折線的方案就對應了一類不同的放球序列,
但是如果幾條折線你可以上下平移得到就算重了,要保證不重的話,直接讓最低點在\(x\)軸上即可。
設\(f_{i,j,0/1}\)表示當前在第\(i\)輪,剩\(j\)個黑球,最低點是否到達過\(x\)軸,分類討論一下即可。
代碼
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int Mod = 1e9 + 7;
const int MAX_N = 3e3 + 5;
int N, M;
int f[MAX_N][MAX_N][2];
void pls(int &x, int y) { x += y; if (x >= Mod) x -= Mod; }
int main () {
cin >> N >> M;
f[0][0][1] = 1;
for (int i = 1; i <= N; i++) f[0][i][0] = 1;
for (int i = 0; i < M; i++)
for (int j = 0; j <= N; j++) {
if (j >= 1) {
//2 black
pls(f[i + 1][j - 1][1], f[i][j][1]);
if (j == 1) pls(f[i + 1][j - 1][1], f[i][j][0]);
else pls(f[i + 1][j - 1][0], f[i][j][0]);
}
if (j < N) {
//2 white
pls(f[i + 1][j + 1][1], f[i][j][1]);
pls(f[i + 1][j + 1][0], f[i][j][0]);
}
if (j >= 1) {
//1 black 1 white
pls(f[i + 1][j][1], f[i][j][1]);
if (j == 1) pls(f[i + 1][j][1], f[i][j][0]);
else pls(f[i + 1][j][0], f[i][j][0]);
}
if (j < N) {
//1 white 1 black
pls(f[i + 1][j][1], f[i][j][1]);
pls(f[i + 1][j][0], f[i][j][0]);
}
}
int ans = 0;
for (int i = 0; i <= N; i++) pls(ans, f[M][i][1]);
printf("%d\n", ans);
return 0;
}