A. 对对碰

交互 1000 ms 256 MiB

题目描述

这是一道交互题。如果你此前没有接触过交互题,请参考 OI Wiki - STDIO 交互 的相关介绍,并阅读本题的提示部分。

LCL. 最近沉迷于一款“记忆对对碰”小游戏。这款小游戏包含一个 n×mn\times m 的网格,每个小方格上都放置一个背面朝上的卡片,卡片的正面绘制有若干种不同类型的图案(保证每种类型的图案出现偶数次)。在游戏开始后,玩家可以任意选择网格中背面朝上的卡片,并将其翻转。在任意时刻,如果网格中存在两个正面朝上且图案相同的卡片,这两张卡片将会立即消失;如果网格中存在两个正面朝上且图案不同的卡片,这两张卡片会立即被翻转为背面朝上。在玩家执行若干次翻转操作后,如果网格中的卡片已经全部消失,那么玩家将取得胜利。

LCL. 希望你能够通过严格小于 2nm2nm 次翻转取得游戏的胜利,你能做到吗?

输入格式

第一行两个正整数 n,m(1n,m100)n,m(1\le n,m\le 100),表示网格的大小。保证 n×mn\times m 为偶数。

对于你的每一次翻转操作,交互器会提供一个字符串 ss,表示此次翻转卡片的图案类型。保证 ss 的长度不超过 2020,且仅由大小写英文字母组成。

特别地,如果在完成此次翻转操作后,玩家已经取得胜利,交互器会提供一个字符串 “Accepted.”\texttt{“Accepted.”}(不包含引号)。当交互器提供 “Accepted.”\texttt{“Accepted.”} 后,你的程序应当立即结束。

请注意,交互器并不会提供有关当前卡片是否会消失或被自动翻转的信息,因此你需要在自己的程序中维护这些信息。

输出格式

对于每一次翻转操作,按照 ? x y\texttt{? x y} 的方式输出,表示翻转第 xx 行第 yy 列的卡片。

如果你的输出不在游戏的网格范围内,或者尝试翻转一个已经是正面朝上的卡片,或者翻转一张已经消失的卡片,你将会得到 Wrong Answer。

如果你的操作次数大于等于 2nm2nm,你同样会得到 Wrong Answer。

在输出一次翻转操作后,不要忘记输出换行符并刷新标准输出。请使用:

  • C 中的 fflush(stdout)
  • C++ 中的 std::cout.flush()
  • Java 中的 System.out.flush()
  • Pascal 中的 flush(output)
  • Python 中的 stdout.flush()
  • 有关其他语言,请阅读其参考文档。

样例

输入样例 1:

2 3

Cat

Cat

Dog

Pig

Dog

Dog

Pig

Accepted.

输出样例 1:

? 1 1

? 1 2

? 1 3

? 2 1

? 1 3

? 2 2

? 2 1

? 2 3

样例说明 1:

+-----+-----+-----+
| Cat | Cat | Dog |
+-----+-----+-----+
| Pig | Dog | Pig |
+-----+-----+-----+

数据范围与提示

1. 关于交互

你可以参考以下 C++ 的代码实现,用于尝试翻转指定位置的卡片并读取结果。

// 调用这一函数时,请确保:
// 1. (x, y) 位置的卡片没有消失
// 2. (x, y) 位置的卡片为背面朝上
// 并且调用这一函数的次数小于 2nm
std::string try_flip(int x, int y) {
    std::cout << "? " << x << " " << y;
    std::cout << std::endl; // 使用 std::endl 无需 flush
    std::string res;
    std::cin >> res;
    if (res == "Accepted.") {
        exit(0);
    }
    return res;
}

2. 关于评测结果

  • 如果你的翻转次数大于等于 2nm2nm 次,你会得到 Wrong Answer
  • 如果你的程序还没有收到 Accepted. 就提前结束,你会得到 Time Limit Exceeded
  • 如果你的输出格式不符合要求,你会得到 Wrong Answer
  • 如果你尝试翻转的卡片已经消失或者为正面朝上,你会得到 Wrong Answer
  • 如果你在输出查询后没有刷新标准输出,你可能会得到 Time Limit Exceeded