专栏文章

题解:P14256 平局(draw)

P14256题解参与者 3已保存评论 4

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
4 条
当前快照
1 份
快照标识符
@minkmu2w
此快照首次捕获于
2025/12/02 03:57
3 个月前
此快照最后确认于
2025/12/02 03:57
3 个月前
查看原文
验题人题解。
以下讨论都在模 33 意义下进行。
约定石头为 22,剪刀为 11,布为 00,即 xx 击败 (x1)(x-1)
两个观察:
  1. 如果出现两个相同的手势,则可以直接消去一个。
  2. 如果出现形如 x,x1,xx,x-1,x 的情况,则可以替换成一个 xx
    证明考虑如果要让中间的 x1x-1 对答案有贡献,则左右两边的 xx 必须损失一个,答案不会变大。
把这两种情况全部消去,剩下的数必定形如:
,x2,x1a,x,x1,x2,b\underbrace{\dots,x-2,x-1}_a,x,\underbrace{x-1,x-2,\dots}_b
考虑在 xx 前面有 aa 项,xx 后面有 bb 项,则答案为 a3+b3+[ab2(mod3)]\left \lfloor \frac a3 \right \rfloor + \left \lfloor \frac b3 \right \rfloor + \left [ a\equiv b\equiv 2 \pmod{3} \right ] ,容易手模出来。
现在我们再观察前面的两种情况,如果我们已经知道前 ii 个人的 a,ba,b 值,考虑下一个人:
  1. 相当于直接消去,对 a,ba,b 无影响。
  2. bb1b\gets b-1
于是我们就可以直接 dp 了。设当前考虑到 ii,第 ii 个人的选择出 xx,当前的 aabb。考虑下一个人出 xx'
  • x=xx=x':发生上面第一种情况,a=a,b=ba'=a,b'=b
  • x+1=xx+1=x':如果 b=0b=0,则不会发生上面的第二种情况,a=a+1,b=ba'=a+1,b'=b;否则 a=a,b=b1a'=a,b'=b-1
  • x1=xx-1=x'a=a,b=b+1a'=a,b'=b+1
每当发生消去时,答案要额外 +1+1,记录方案数和当前的答案,即可做到 O(n3)O(n^3)。注意到 aa 不降,于是只用记录 amod3a \bmod 3 即可,时间复杂度 O(n2)O(n^2)
代码CPP
constexpr int N = 3005;
char s[N];
Mint f[N][3][N][3], g[N][3][N][3];
vi possible[N];

// signed main() {
int main() {
  // freopen("draw3.in", "r", stdin);
  // freopen(".out", "w", stdout);
  ios::sync_with_stdio(false);
  cin.tie(0);

  int n;
  cin >> n;
  cin >> reinterpret_cast<char (&)[N]>(s[1]);
  for (int i = 1; i <= n; i++) s[i] -= '0';
  for (int i = 1; i <= n; i++) {
    for (auto j : {0, 1, 2})
      if (s[i] >> j & 1) possible[i].pb(j);
  }
  for (auto x : possible[1]) g[1][0][0][x] = 1;
  for (int i = 1; i < n; i++) {
    for (auto x : possible[i]) {
      for (int upl = 0; upl < 3; upl++) {
        for (int downl = 0; downl < i; downl++) {
          auto &F = f[i][upl][downl][x], &G = g[i][upl][downl][x];
          if (F != 0 || G != 0) {
            for (auto nx : possible[i + 1]) {
              if (x == nx) {
                g[i + 1][upl][downl][nx] += G;
                f[i + 1][upl][downl][nx] += F + G;
              } else if ((x + 1) % 3 == nx) {
                if (downl == 0) {
                  g[i + 1][(upl + 1) % 3][downl][nx] += G;
                  f[i + 1][(upl + 1) % 3][downl][nx] += F + G * (upl == 2);
                } else {
                  g[i + 1][upl][downl - 1][nx] += G;
                  f[i + 1][upl][downl - 1][nx] += F + G;
                }
              } else {
                g[i + 1][upl][downl + 1][nx] += G;
                f[i + 1][upl][downl + 1][nx] += F;
              }
            }
          }
        }
      }
    }
  }
  Mint ans = 0;
  for (auto x : possible[n]) {
    for (int upl = 0; upl < 3; upl++) {
      for (int downl = 0; downl < n; downl++) {
        auto &F = f[n][upl][downl][x], &G = g[n][upl][downl][x];
        ans += F + G * (downl / 3 + (upl == 2 && downl % 3 == 2));
      }
    }
  }
  cout << ans << endl;

  return 0;
}

评论

4 条评论,欢迎与作者交流。

正在加载评论...