Loading

P2575 高手过招 题解

题目描述

我们考虑如何把问题转换成博弈论来求解。

我们对于每一行之前都加上一个空格。
设原来这一行的空格个数是 \(C\) ,那么此时空格个数变成 \(C + 1\)
然后按照从左到右的顺序给每一个空格标号。

接着构建出一个数组 \(p_i\)
\(p_i\) 表示从第 \(i\) 个空格开始后面有多少个连续的棋子。
比如像这样的一行棋盘:

\[\circ\circ\bullet\circ\circ\bullet\bullet\bullet\circ\circ\bullet\circ\bullet \]

我们先在前面加上一个空格

\[(\circ)\circ\circ\bullet\circ\circ\bullet\bullet\bullet\circ\circ\bullet\circ\ \bullet \]

不难发现,此时我们的 \(p\) 数组是这样的:

\[\{0,0,1,0,3,0,1,1\} \]

我们可以发现如果我们移动第 \(2\) 个棋子会变成这样。

\[(\circ)\circ\circ\bullet\circ\circ\circ\bullet\bullet\bullet\circ\bullet\circ\ \bullet\\ p = \{0,0,1,0,0,3,1,1\} \]

同理,我们可以发现所有的操作都可以把转换成 \(p\) 上的操作。

我们尝试着把 \(p_i\) 当作是第 \(i\) 个阶梯上的石子个数。
题目上的限制是移到右边最近的一个空格上。
让后通过模拟 \(2\sim 4\) 的棋子(再次不在给出结果)可以发现相当于是指定棋子向上一层移动。
(当然,最多只会向上一层移动,可以证明不会影响到其他的地方)

当所有的棋子变成这样时就结束了

\[\circ\circ\circ\circ\circ\bullet\bullet\bullet\bullet\bullet\bullet \]

同理,也可以对应到所有的石子被移到最高层。
所以就是个 阶梯 \(\textbf{Nim}\)

Code

#include <bits/stdc++.h>

#define file(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)

#define quad putchar(' ')
#define Enter putchar('\n')

const int N = 30;

int T, n, ans2, a[N], ans1;

signed main(void) {
//  file("P2575");
  std::cin >> T;
  for (int test = 1; test <= T; test ++) {
    std::cin >> n;
    ans2 = 0;
    for (int i = 1, m; i <= n; i++) {
      scanf("%d", &m);
      memset(a, 0, sizeof(a)); ans1 = 0;
      int cnt = 20 - m + 1;
      for (int i = 1, pos; i <= m; i++) {
        scanf("%d", &pos);
        a[pos] = 1;
      }
      int tot = 0;
      for (int i = 1; i <= 20; i++) {
        if (a[i] == 0) {
          cnt --;
          if (cnt % 2 == 1)
            ans1 ^= tot;
          tot = 0;
        } else tot ++;
      }
      ans2 ^= ans1;
    }
    if (ans2 == 0) std::cout << "NO" << std::endl;
    else std::cout << "YES" << std::endl;
  }
}
posted @ 2022-04-24 23:22  Aonynation  阅读(50)  评论(0编辑  收藏  举报