题意

有 \(n\) 个格子排成一行,一开始每个格子上涂了蓝色或红色。

Alice 和 Bob 用这些格子做游戏。Alice 先手,两人轮流操作:

  • Alice 操作时,选择两个相邻的格子,其中至少要有一个红色格子,然后把这两个格子涂成白色;
  • Bob 操作时,选择两个相邻的格子,其中至少要有一个蓝色格子,然后把这两个格子涂成白色。

注意白色的格子也可以被选中,只要满足“至少一个红/蓝色格子”的条件。当轮到一方操作,但该方无法进行操作时,另一方获胜。

如果两人都采取最优策略,谁会获胜?

\(n \le 5 \times 10^5\)。

解析

首先贪心地想,两人会采取什么策略?不妨把游戏看成一个“轮次”的游戏,红色格子是 A 的轮次,蓝色格子是 B 的轮次。显然双方都想让自己的轮次尽可能多,对方尽可能少。由于每次操作至少选择一个己方的颜色,所以每轮会至少消耗一个己方轮次。

  • 如果是两个己方颜色,则会消耗两个己方轮次,显然不优;
  • 如果是己方颜色和白色,则只消耗一个己方轮次;
  • 如果是己方颜色和对方颜色,则不仅只消耗一个己方轮次,还会减少一个对方轮次,应该是比较优的策略。

换句话说,会优先选策略三;然后会选择策略二;最后,其实容易发现除非全是红色,否则不会用到策略一,因为可以替代成两次策略二。

于是只考虑策略二三。观察策略的特点,当两人都在采取策略三时,两人的轮次差是不变的,而采取策略二时:

  • 如果两人剩余轮次数不同,则剩余轮次多的人获胜;
  • 如果两人剩余轮次数相同,则后手获胜,或者说,取走最后一个 RBBR 的一方获胜。

于是我们可以判断:

  • 如果两种颜色的数量不同,则较多的颜色对应的玩家必胜;
  • 如果两种颜色相同,则取走最后一个 RBBR 的一方获胜。

第二种情况如何考虑?既然只需要考虑 RBBR,我们可以简化字符串,简化后就是 RBRBRBR...。只是这样一段 RB 交替的串吗?也可以几个串连起来(用 | 划分串)RBR|RBRB|BRB。注意到采取策略三时,我们不可能跨串选择格子(因为这样的两个格子是同色的),于是每个串是独立的子游戏

独立的子游戏”?nim游戏?SG函数?尝试用 SG 函数解题。那么整个游戏的 SG 值是每个串的 SG 值的异或和。

考虑一个串的 SG 值,由于是 RB 交替的,我们发现这个串里 R 多还是 B 多其实没有影响(比如 RBRBRB 其实没有区别),这样一来,一个串就可以用其长度代替了。记 \(SG(i)\) 表示长度为 \(i\) 的串的 SG 值,考虑选择 \(i, i + 1\) 两个格子,会将串分成两个长度分别为 \(i - 1, n - i - 1\) 的两个串,而这两个串又互不影响了,转移到的状态的 SG 值就是这两个串的 SG 值异或,则

\[SG(n) = \text{mex}_{1 \le i \le n - 1}\Big\{SG(i - 1)\text{ xor }SG(n - i - 1)\Big\}
\]

这样我们可以 \(O(n^2)\) 计算 \(SG(n)\)。但这样显然不够……怎么优化?不能优化?那把表打出来看看……好像是以 \(34\) 为周期?除了前 \(68\) 个,剩下的以 \(34\) 为周期,于是可以先暴力算出 \(SG(0 \sim 1000)\),然后按周期推 \(SG(0 \sim n)\)。

代码

#include <cstdio>
#include <cstring>
#include <algorithm> const int MAXN = 5e5 + 10; char col[MAXN];
int sg[MAXN];
bool tmp_is_exi[1005]; void calcSg()
{
sg[0] = 0;
for (int n = 1; n <= 1000; ++n)
{
memset(tmp_is_exi, 0, sizeof tmp_is_exi);
for (int i = 1; i < n; ++i)
{
tmp_is_exi[sg[i - 1] ^ sg[n - i - 1]] = true;
}
for (int i = 0; ; ++i)
{
if (!tmp_is_exi[i])
{
sg[n] = i;
break;
}
}
}
for (int i = 1001; i < MAXN; ++i)
{
sg[i] = sg[i - 34];
}
}
bool solveCase()
{
int len;
scanf("%d%s", &len, col + 1);
int cnt_red = 0;
for (int i = 1; i <= len; ++i)
{
cnt_red += col[i] == 'R';
}
if (cnt_red != len - cnt_red)
{
return cnt_red > len - cnt_red;
}
int las = 1, overall_sg = 0;
for (int i = 1; i < len; ++i)
{
if (col[i] == col[i + 1])
{
overall_sg ^= sg[i - las + 1];
las = i + 1;
}
}
overall_sg ^= sg[len - las + 1];
return overall_sg != 0;
} int main()
{
calcSg();
int cnt_cas;
scanf("%d", &cnt_cas);
while (cnt_cas--)
{
printf("%s\n", solveCase() ? "Alice" : "Bob");
}
return 0;
}

「postOI」Colouring Game的更多相关文章

  1. 「译」JUnit 5 系列:条件测试

    原文地址:http://blog.codefx.org/libraries/junit-5-conditions/ 原文日期:08, May, 2016 译文首发:Linesh 的博客:「译」JUni ...

  2. 「译」JUnit 5 系列:扩展模型(Extension Model)

    原文地址:http://blog.codefx.org/design/architecture/junit-5-extension-model/ 原文日期:11, Apr, 2016 译文首发:Lin ...

  3. JavaScript OOP 之「创建对象」

    工厂模式 工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程.工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题. function createPers ...

  4. 「C++」理解智能指针

    维基百科上面对于「智能指针」是这样描述的: 智能指针(英语:Smart pointer)是一种抽象的数据类型.在程序设计中,它通常是经由类型模板(class template)来实做,借由模板(tem ...

  5. 「JavaScript」四种跨域方式详解

    超详细并且带 Demo 的 JavaScript 跨域指南来了! 本文基于你了解 JavaScript 的同源策略,并且了解使用跨域跨域的理由. 1. JSONP 首先要介绍的跨域方法必然是 JSON ...

  6. 「2014-5-31」Z-Stack - Modification of Zigbee Device Object for better network access management

    写一份赏心悦目的工程文档,是很困难的事情.若想写得完善,不仅得用对工具(use the right tools),注重文笔,还得投入大把时间,真心是一件难度颇高的事情.但,若是真写好了,也是善莫大焉: ...

  7. 「2014-3-18」multi-pattern string match using aho-corasick

    我是擅(倾)长(向)把一篇文章写成杂文的.毕竟,写博客记录生活点滴,比不得发 paper,要求字斟句酌八股结构到位:风格偏杂文一点,也是没人拒稿的.这么说来,arxiv 就好比是 paper 世界的博 ...

  8. 「2014-3-17」C pointer again …

    记录一个比较基础的东东-- C 语言的指针,一直让人又爱又恨,爱它的人觉得它既灵活又强大,恨它的人觉得它太过于灵活太过于强大以至于容易将人绕晕.最早接触 C 语言,还是在刚进入大学的时候,算起来有好些 ...

  9. 「2014-3-13」Javascript Engine, Java VM, Python interpreter, PyPy – a glance

    提要: url anchor (ajax) => javascript engine (1~4 articles) => java VM vs. python interpreter =& ...

  10. 「2014-2-26」Unicode vs. UTF-8 etc.

    目测是个老问题了.随便一搜,网上各种总结过.这里不辞啰嗦,尽量简洁的备忘一下. 几个链接,有道云笔记链接,都是知乎上几个问题的摘录:阮一峰的日志,1-5 还是值得参考,但是之后的部分则混淆了 Wind ...

随机推荐

  1. OPA-CH32x系列芯片OPA使用注意事项

    1 OPA运放基本功能说明 1.1 OPA引脚详细说明方式 说明方式1如下所示: OPN0.OPP0.OPO为OPA的第0通道 OPN0:OPA_0通道的N端 OPP0:OPA_0通道的P端 OPO: ...

  2. Vue3 企业级优雅实战 - 组件库框架 - 10 实现组件库 cli - 下

    上文创建了一堆 utils.component-info,并实现了新组件模块相关目录和文件的创建.本文继续实现后面的内容. 1 组件样式文件并导入 在 src/service 目录中创建 init-s ...

  3. SQL优化的七个方面

    SQL优化的七个方面 1. 创建索引 禁止给表中每一列都建立单独索引 每个Innodb表都必须有一个主键 要注意组合索引的字段顺序 优先考虑覆盖索引 避免使用外键约束 2. 避免索引失效 失效场景: ...

  4. 构建api gateway之 openresty 中如何使用 wasm

    openresty 中如何使用 wasm WASM 是什么? WebAssembly是一种运行在现代网络浏览器中的新型代码,并且提供新的性能特性和效果.它设计的目的不是为了手写代码而是为诸如C.C++ ...

  5. .NET WebAPI 跨域问题(has been blocked by CORS policy:No Access-Control-Allow-Ogigin header is present on the requested resource)

    一.什么是跨域 1. 跨域解释 跨域指的是浏览器不能执行其他网站的脚本.它是由浏览器的同源策略造成的,是浏览器施加的安全限制. 同源指的是:域名,协议,端口均相同. 2. 什么情况下会导致跨域 2.1 ...

  6. P10_组件-text和rich-text组件的基本用法

    常用的基础内容组件 text 文本组件 类似于 HTML 中的 span 标签,是一个行内元素 rich-text 富文本组件 支持把 HTML 字符串渲染为 WXML 结构 text 组件的基本使用 ...

  7. 有趣的python库-pillow

    pillow-图像处理 安装时不再是PIL,是pillow哦! 烟花 pillow + tkinter实现 import tkinter as tk from PIL import Image, Im ...

  8. 有趣的python库-turtle

    turtle-绘制图像用 画樱花树 import turtle as tt import random # 画樱花的躯干(60,t) def tree(branch, t): if branch &g ...

  9. Express 项目 Cookie 不能保存在 Application 中

    在前后端分离项目中,因为跨域策略,所以 Cookie 不能存储在浏览器的 Application 中.只能在请求的响应头处看到有 Set-Cookie: 1️⃣前端发送请求添加 withCredent ...

  10. 04#Web 实战:Gitee 贡献图

    前言 这次要做的 Web 前端实战是一个 Gitee 个人主页下的贡献图(在线 Demo),偶尔做一两个,熟悉熟悉 JS 以及 jQ.整体来说这个案例并不难,主要是控制第一个节点以及最后一个节点处于星 ...