ARC089D ColoringBalls
这个题是求颜色序列的方案数,一种颜色序列可能由多种操作序列映射得到。
考虑序列
按照这个思路,手玩一下可以发现,若一段红蓝交错的颜色序列中有
这题有长度
发现一个操作序列映射到的是颜色段序列,也就是说我们可以把每个颜色段缩成一个颜色点,求出颜色点序列的方案数之后,再乘一些组合系数就可以得到颜色段序列的方案数。这样我们就可以先忽略掉
颜色点序列一定是若干个红色序列或红蓝序列,被若干个黑色序列分隔开来。
此时给你操作序列
如果不能按照上述方案分配
如果可以分配,就把提前分配出去的
我们只要确定了
然而还需要考虑构造这
设
则需要满足
显然令
那么就可以考虑 DP 了。
设
则
观察这个式子,直接转移是
至于
分出
现在考虑还原颜色段序列,即相当于要在每个点填充若干个元素,其中某些点可以填
首先每段红蓝序列都有
红蓝序列共有
综上得到
算上枚举
注意枚举
#include <bits/stdc++.h>
#define MAX_N (70 + 5)
#define ll long long
using namespace std;
const int mod = 1e9 + 7;
int n, m;
char s[MAX_N];
bool vis[MAX_N];
int sum[MAX_N];
int f[MAX_N][MAX_N][MAX_N];
int C[505][505];
bool Init(int x, int y) {
int cnt1 = 0, cnt2 = 0;
for (int i = 1; i <= m; ++i) {
if (s[i] == 'r') {
if (cnt1 < x + y) ++cnt1, vis[i] = 0;
else vis[i] = 1;
}
else {
if (cnt2 < x && cnt1 > cnt2) ++cnt2, vis[i] = 0;
else vis[i] = 1;
}
}
if (cnt1 < x + y || cnt2 < x) return false;
int tmp = 0, cur = x;
for (int i = m; i; --i) {
if (vis[i]) ++tmp;
else if (s[i] == 'b') sum[cur--] = tmp;
}
return true;
}
int main() {
n = 500;
for (int i = 0; i <= n; ++i) {
C[i][0] = 1;
for (int j = 1; j <= i; ++j)
C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
}
scanf("%d%d%s", &n, &m, s + 1);
int ans = 0;
for (int x = 0; x <= m; ++x) {
for (int y = 0; 2 * x + y <= m; ++y) {
if (!Init(x, y)) break;
int len = sum[1];
for (int i = 0; i <= len; ++i)
f[x + 1][0][i] = 1;
for (int i = x; i; --i) {
for (int k = 0; k <= len; ++k)
f[i][0][k] = 1;
for (int j = 1; j <= sum[i] && 2 * j + 2 * x + 2 * y - 1 <= n; ++j) {
for (int k = 1; k <= len; ++k) {
for (int l = 1; i + l <= x + 1 && j - k * l >= 0 && j - k * l <= sum[i + l]; ++l)
f[i][j][k] = (f[i][j][k] + (ll)f[i + l][j - k * l][k - 1] * C[x - i + 1][l]) % mod;
f[i][j][k] = (f[i][j][k] + f[i][j][k - 1]) % mod;
}
}
}
int res = 0;
for (int j = 0; j <= len && 2 * j + 2 * x + 2 * y - 1 <= n; ++j)
res = (res + (ll)f[1][j][len] * C[n + 2 * x + 1][4 * x + 2 * y + 2 * j]) % mod;
res = (ll)res * C[x + y][y] % mod;
ans = (ans + res) % mod;
for (int i = 0; i <= len; ++i)
f[x + 1][0][i] = 0;
for (int i = x; i; --i)
for (int j = 0; j <= sum[i]; ++j)
for (int k = 0; k <= len; ++k)
f[i][j][k] = 0;
for (int i = 1; i <= x + y; ++i)
sum[i] = vis[i] = 0;
}
}
ans = (ans + mod) % mod;
printf("%d", ans);
return 0;
}