首页 > 其他分享 >[AGC064D] Red and Blue Chips 题解

[AGC064D] Red and Blue Chips 题解

时间:2024-10-09 11:44:42浏览次数:8  
标签:Blue kMod int 题解 sum kMaxN bs 字符串 Chips

Description

你有 \(N\) 个字符串,初始情况下每个字符串只有一个字符,是 \(\texttt{R}\) 或 \(\texttt{B}\),保证第 \(N\) 个字符串是 \(\texttt{B}\)。

你需要对每个 \(i=1,2,\cdots ,n-1\) 执行以下操作:

  • 选择一个整数 \(j\) 使得 \(i< j\le n\),且第 \(j\) 个字符串的最后一个字符是 \(\texttt{B}\),然后把第 \(i\) 个字符串整体拼接在第 \(j\) 个字符串的前面

问最后可以得到多少种本质不同的第 \(N\) 个字符串,对 \(998244353\) 取模。

\(2\leq N\leq 300,s_N=\texttt{B}\)。

Solution

考虑怎么判断一个终止串 \(t\) 是否合法。

容易发现终止串形如一棵树的后序遍历的形式,所以可以倒着为每个位置找父亲。

在找父亲的过程中把终止串挂在最后一个 B 上,设 \(m\) 为原串 B 的个数,\(f_i\) 表示挂在 \(i\) 上的串。

设当前走到了 \(i\),如果当前 \(s_i\) 为 R,就选择一个 \(f_j\) 满足 \(f_j\) 开头为 R 并把开头的 R 删掉,表示 \(i\) 的父亲为 \(j\)。否则就需要把某个 \(f_j\) 在字符为 B 的位置分裂,并且把分裂后前面的串挂在 \(i\) 上。

由于我们需要尽量让当前所有 \(f_i\) 开头的 R 数量和最多,所以每次选择长度最大的极长 R 段前分裂一定最优。容易发现这么做如果存在一个时刻满足 \(s_i\) 为 R 且所有 \(f_i\) 的开头都不为 R,那么这个串一定不合法。

形式化的描述就是设 \(a_i\) 表示初始串倒数第 \(i\) 个极长 R 连续段的长度,\(b_i\) 表示终止串倒数第 \(i\) 个极长 R 连续段的长度。

又因为 \(b_1\) 显然不能动,所以只能对 \(b_2,b_3,\ldots,b_m\) 排序,排序后合法的充分必要条件为 \(\forall j\in[1,m],\sum_{i=1}^{j}{a_i}\leq\sum_{i=1}^{j}{b_i}\)。

方案数容易 dp 得到。

时间复杂度:\(O(n^3\ln n)\)。

Code

#include <bits/stdc++.h>

#define int int64_t

const int kMaxN = 305, kMod = 998244353;

int n, m;
int a[kMaxN], sum[kMaxN], f[kMaxN][kMaxN], fac[kMaxN], ifac[kMaxN];
std::string str;

constexpr int qpow(int bs, int64_t idx = kMod - 2) {
  int ret = 1;
  for (; idx; idx >>= 1, bs = (int64_t)bs * bs % kMod)
    if (idx & 1)
      ret = (int64_t)ret * bs % kMod;
  return ret;
}

inline int add(int x, int y) { return (x + y >= kMod ? x + y - kMod : x + y); }
inline int sub(int x, int y) { return (x >= y ? x - y : x - y + kMod); }
inline void inc(int &x, int y) { (x += y) >= kMod ? x -= kMod : x; }
inline void dec(int &x, int y) { (x -= y) < 0 ? x += kMod : x; }

void prework(int n = 300) {
  fac[0] = ifac[0] = 1;
  for (int i = 1; i <= n; ++i) {
    fac[i] = 1ll * i * fac[i - 1] % kMod;
    ifac[i] = qpow(fac[i]);
  }
}

void dickdreamer() {
  std::cin >> n >> str;
  int lst = 0;
  for (int i = 1; i <= n; ++i) {
    if (str[i - 1] == 'B') {
      a[++m] = i - lst - 1;
      lst = i;
    }
  }
  prework();
  std::reverse(a + 1, a + 1 + m);
  for (int i = 1; i <= m; ++i) sum[i] = sum[i - 1] + a[i];
  int cnt = n - m;
  for (int i = a[1]; i <= cnt; ++i) f[1][i] = fac[m - 1];
  for (int i = cnt; ~i; --i) {
    for (int j = m; j; --j) {
      for (int k = cnt; k >= sum[j]; --k) {
        for (int c = 1; c <= std::min(j, (i ? k / i : n)); ++c) {
          if (k - i * (c - 1) >= sum[j - c + 1]) inc(f[j][k], 1ll * f[j - c][k - i * c] * ifac[c] % kMod);
          else break;
        }
      }
    }
  }
  std::cout << f[m][cnt] << '\n';
}

int32_t main() {
#ifdef ORZXKR
  freopen("in.txt", "r", stdin);
  freopen("out.txt", "w", stdout);
#endif
  std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
  int T = 1;
  // std::cin >> T;
  while (T--) dickdreamer();
  // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
  return 0;
}

标签:Blue,kMod,int,题解,sum,kMaxN,bs,字符串,Chips
From: https://www.cnblogs.com/Scarab/p/18453908

相关文章

  • AT_jsc2021_h Shipping 题解
    不算难的一道题。思路考虑原图是一个基环树。首先在树上部分的路径是固定的,我们没有办法抉择。唯一需要考虑的是在环上的那一部分。在环上我们每一个路径有两种选择。如何考虑到所有情况。我们每一次断掉环上的一条边。这样每一个路径就变成固定的了。我们只需要快速计算......
  • Hetao P1031 萌萌题 题解 [ 蓝 ] [ 线性 dp ]
    萌萌题:一道结合了观察性质的线性dp。观察我们先考虑极端情况:所有数相同,所有数降序排列两种情况。对于所有数相同的情况,我们发现,最终可以合并出来的区间,最多只有\(n\logn\)个。怎么证明?考虑固定右端点,那么我们想要合并出一个点,就得选\(2^k\)个数出来,这就有\(\logn\)......
  • [AGC064C] Erase and Divide Game 题解
    DescriptionTakahashi和Aoki玩游戏。先在黑板上写若干个数,由\(N\)个互不相交的区间\([l_i,r_i]\)组成。两人轮流操作,每次操作先删去所有的奇数/偶数,再把剩下的数除以\(2\)(向下取整),无法操作的人输。Takahashi先手,假设两人都采用最优策略,问谁能获胜。\(1\leqN\leq10^......
  • 移动端window.open跳转链接时,iOS没有反应的问题解决
    问题描述:使用window.open跳转链接时安卓可以正常跳转,但是iOS苹果上没有反应问题原因:用户交互限制iOS对于window.open的调用有严格的用户交互要求。如果window.open不是在用户交互(如点击事件)的上下文中调用的,可能会被浏览器阻止。弹出窗口拦截某些浏览器可能会默认......
  • 士兵训练 题解
    题意link.题解正解会RE几个点,是官方的栈空间太小了。再者网上几篇题解都被我hack了,好不容易找到一组hack却不是我错了,而是STD错了……所以我来写篇题解造福社会。观察到\(\max\{b_i\bmodb_j\}\),则得到的结果一定比最大值小,则最大能取到次大。那就维护一个子树......
  • 【问题解决】remote: parse error: Invalid numeric literal at line 1, column 20,解
    问题现象某同事出现过同样的推送到git仓库报错的问题,报错信息详情如下:Deltacompresionusingupto20threadsCompressingobjects:100%(4/4),done.Writingobjects:100%(5/5),521bytes|521.00KiB/s,done.Total5(delta3),reused0(delta0),pack-reused0r......
  • 系统开发基础错题解析一【软考】
    目录前言1.开发模型1.1快速原型模型优点1.2敏捷统一模型1.3增量模型的优缺点1.4极限编程1.5螺旋模型2.软件开发方法3.数据流图与数据字典3.1判定表3.2数据流图绘制3.3决策树4.概要设计和详细设计5.内聚性6.耦合性前言本文专门用来记录本人在做软考中有关系统开发基......
  • [AGC061C] First Come First Serve 题解
    Description有\(n\)个人来过,第\(i\)个人在\(a_i\)时刻来在\(b_i\)时刻走,每个人可以在来时或走时登记,问可能的登记顺序有多少种。\(n\leq5\times10^5\),\(a_i,b_i\)互不相同,\(\foralli<n,a_i<a_{i+1},b_{i}<b_{i+1}\)。Solution首先如果每个人随便选,有\(2^n\)种方......
  • [ARC112F] Die Siedler 题解
    智慧题。思路考虑第二种操作。我们会想到,我们可以先把所有牌转化成第一种牌。即:\[one=\sum_{i=1}^n\prod_{j=1}^i2^{j-1}(j-1)!c_i\]这就是第一种牌的数量。然后考虑,我们可以将第一种牌转化为第一种牌,花费的代价为:\[g=(\prod_{i=1}^n2^{i-1}(i-1)!)-1\]相当于对\(g\)......
  • P1437 [HNOI2004] 敲砖块 题解
    初拿到手感觉限制太多了,不好硬做,于是开始观察。若要取某一个数,我们要取其左上右上两个数,而这两个数又要取上面三个数,所以取一个数的前提条件其实是取这一个三角形。举例2234582712236493比如我要取第3行的6,我首先要取7和12,要取7和12,首先要取3,4,5,所以一层层拓展......