AT_agc064_d [AGC064D] Red and Blue Chips
高妙 counting 题/bx/bx/bx。
记原串
由于要求本质不同,所以先思考这样一个问题,给定一个字符串 check 是否有一种操作方案使得最终第
把
先考虑扣掉后面
接下来考虑如何 check 这个条件。直接把
因为子序列匹配不要求这些段在原串中依次出现,所以我们可以按任意顺序去匹配。贪心策略是:让最长的段去匹配最靠右的
记
前
于是考虑 dp 求解。从大到小枚举段长,每次确定这个长度出现了多少次。
设
初始时还没有确定任何一段,只需枚举末尾长度
接下来处理长度
需要保证转移后仍然合法,故有:
从剩余的
答案即为:
对于每个正长度
加上组合数预处理,总时间复杂度为
:::success[Code]
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int ll
const int mod = 998244353;
int n, f[307][307], g[307][307], C[307][307], b[307], tot = 0;
string s;
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
C[0][0] = 1;
for (int i = 1; i < 307; i++)
{
C[i][0] = C[i][i] = 1;
for (int j = 1; j < i; j++)
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
}
cin >> n >> s;
s = '#' + s;
int t = 0;
for (int i = n - 1; i >= 1; i--)
if (s[i] == 'R')
t++;
else
b[++tot] = t;
b[tot + 1] = t;
for (int i = b[1]; i <= t; i++)
f[0][i] = 1;
for (int i = t; i >= 1; i--)
{
memset(g, 0, sizeof(g));
for (int j = 0; j <= min(tot, t / (i + 1)); j++)
for (int k = 0; k <= t; k++)
for (int l = 0; l <= min(tot - j, (t - k) / i); l++)
{
int nj = j + l, nk = k + l * i;
if (nk < b[nj + 1])
break;
(g[nj][nk] += f[j][k] * C[tot - j][l] % mod) %= mod;
}
for (int j = 0; j <= tot; j++)
for (int k = 0; k <= t; k++)
f[j][k] = g[j][k];
}
int res = 0;
for (int j = 0; j <= tot; j++)
(res += f[j][t]) %= mod;
cout << res;
}
:::