Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 1386  Solved: 840
[Submit][Status][Discuss]

Description

聪聪和睿睿最近迷上了一款叫做分裂的游戏。该游戏的规则试:共有n个瓶子,标号为0,1,2.....n-1,第i个瓶子中
装有p[i]颗巧克力豆,两个人轮流取豆子,每一轮每人选择3个瓶子。标号为i,j,k,并要保证i<j,j<=k且第i个瓶子
中至少要有1颗巧克力豆,随后这个人从第i个瓶子中拿走一颗豆子并在j,k中各放入一粒豆子(j可能等于k)。如
果轮到某人而他无法按规则取豆子,那么他将输掉比赛。胜利者可以拿走所有的巧克力豆!两人最后决定由聪聪先
取豆子,为了能够得到最终的巧克力豆,聪聪自然希望赢得比赛。他思考了一下,发现在有的情况下,先拿的人一
定有办法取胜,但是他不知道对于其他情况是否有必胜策略,更不知道第一步该如何取。他决定偷偷请教聪明的你
,希望你能告诉他,在给定每个瓶子中的最初豆子数后是否能让自己得到所有巧克力豆,他还希望你告诉他第一步
该如何取,并且为了必胜,第一步有多少种取法?
假定 1 < n < = 21,p[i] < = 10000

Input

输入文件第一行是一个整数t表示测试数据的组数,
接下来为t组测试数据(t<=10)。
每组测试数据的第一行是瓶子的个数n,
接下来的一行有n个由空格隔开的非负整数,表示每个瓶子中的豆子数。

Output

对于每组测试数据,输出包括两行,
第一行为用一个空格两两隔开的三个整数,表示要想赢得游戏,
第一步应该选取的3个瓶子的编号i,j,k,
如果有多组符合要求的解,那么输出字典序最小的一组。
如果无论如何都无法赢得游戏,那么输出用一个空格两两隔开的三个-1。
第二行表示要想确保赢得比赛,第一步有多少种不同的取法。

Sample Input

2
4
1 0 1 5000
3
0 0 1

Sample Output

0 2 3
1
-1 -1 -1
0

HINT

 

Source

又一道神题,一开始一直在分析最后一堆和倒数第二堆,分析出了一坨没卵用的性质

首先,我们按照套路,观察有没有模仿棋性质的操作,发现当豆子个数为偶数的时候后手可以把先手抵消掉

这样的话豆子数实际就变成了一串01序列

我们此时回过头来考虑拿豆子的操作,实际上就是一个multi-nim的模型,然后这题就可做了

因为处理的时候需要用到后面的SG函数,所以用记忆化搜索

输出方案的话。

暴力枚举第一个的位置,然后用异或的性质判断一下

#include<cstdio>
#include<cstring>
const int MAXN=;
inline char nc()
{
static char buf[MAXN*],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,,MAXN*,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
char c=nc();int x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=nc();}
while(c>=''&&c<=''){x=x*+c-'';c=nc();}
return x*f;
}
int N,S[MAXN],SG[MAXN];//游戏可以看做是每个位置独立进行的
int a[MAXN];
int dfs(int now)
{
if(SG[now]!=-) return SG[now];
memset(S,,sizeof(S));
for(int i=now+;i<=N;i++)
for(int j=i;j<=N;j++)
S[ (dfs(i)^dfs(j)) ] = ;
for(int i=;;i++) if(!S[i]) {SG[now]=i;break;}
return SG[now];
}
int main()
{
#ifdef WIN32
freopen("a.in","r",stdin);
#else
#endif
int QwQ=read();
while(QwQ--)
{
memset(SG,-,sizeof(SG));
N=read();
for(int i=;i<=N;i++) a[i]=read();
for(int i=;i<=N;i++)
if(a[i]&) dfs(i);
int ans=,tot=;
for(int i=;i<=N;i++) if(a[i]&)ans=(ans^dfs(i));
for(int i=;i<=N;i++)
for(int j=i+;j<=N;j++)
for(int k=j;k<=N;k++)
{
if( (ans^dfs(i)^dfs(j)^dfs(k) )!=) continue;
tot++;
if(tot==) printf("%d %d %d\n",i-,j-,k-);
}
if(tot==) printf("-1 -1 -1\n");
printf("%d\n",tot);
} return ;
}

BZOJ 1188: [HNOI2007]分裂游戏(multi-nim)的更多相关文章

  1. bzoj 1188 [HNOI2007]分裂游戏(SG函数,博弈)

    1188: [HNOI2007]分裂游戏 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 733  Solved: 451[Submit][Status ...

  2. bzoj 1188 [HNOI2007]分裂游戏 SG函数 SG定理

    [HNOI2007]分裂游戏 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1394  Solved: 847[Submit][Status][Dis ...

  3. [BZOJ 1188] [HNOI2007] 分裂游戏 【博弈论|SG函数】

    题目链接:BZOJ - 1188 题目分析 我们把每一颗石子看做一个单个的游戏,它的 SG 值取决于它的位置. 对于一颗在 i 位置的石子,根据游戏规则,它的后继状态就是枚举符合条件的 j, k.然后 ...

  4. BZOJ 1188 [HNOI2007]分裂游戏

    AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1188 学习SG函数的过程中,我先看了一篇叫做 <2008-贾志豪-组合数学略述... ...

  5. bzoj 1188 : [HNOI2007]分裂游戏 sg函数

    题目链接 给n个位置, 每个位置有一个小球. 现在两个人进行操作, 每次操作可以选择一个位置i, 拿走一个小球.然后在位置j, k(i<j<=k)处放置一个小球. 问你先进行什么操作会先手 ...

  6. 【BZOJ】1188 [HNOI2007]分裂游戏

    [算法]博弈论 [题解] 我们的目的是把游戏拆分成互不影响的子游戏,考虑游戏内的转移. 如果把每堆视为子游戏,游戏之间会相互影响,不成立. 将每堆的一个石子视为子游戏,其产生的石子都在同一个子游戏中. ...

  7. BZOJ P1188 HNOI2007 分裂游戏——solution

    题目描述: (<--这个) 组合游戏,——把每个石头看做一个游戏, Multi_game——消去i上的石子后,,k上的游戏又多了一个: 于是就套用multi_game的模型即可 求解SG函数时, ...

  8. bzoj1188 [HNOI2007]分裂游戏 博弈论 sg函数的应用

    1188: [HNOI2007]分裂游戏 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 973  Solved: 599[Submit][Status ...

  9. [bzoj1188][HNOI2007]分裂游戏_博弈论

    分裂游戏 bzoj-1188 HNOI-2007 题目大意:题目链接. 注释:略. 想法: 我们发现如果一个瓶子内的小球个数是奇数才是有效的. 所以我们就可以将问题变成了一个瓶子里最多只有一个球球. ...

随机推荐

  1. 微信小程序wx.request接口

    微信小程序wx.request接口 wx.request是小程序客户端与服务器端交互的接口 HTTPS 请求 一个微信小程序,只能同时(同时不能大于5个)有5个网络请求 wx.request(OBJE ...

  2. Linux — 文件、目录管理

    目录与路径 .  此层目录 .. 上层目录 -  之前一个工作目录 ~ 主文件夹 ~ account 指定用户的主文件夹,account --账号名称 cd 切换目录 pwd (print worki ...

  3. dom4j 解析XML文件

    <?xml version="1.0" encoding="UTF-8"?> <!-- 手机的根节点 --> <Phones> ...

  4. 一条SQL语句在MySQL中如何执行的

    本篇文章会分析一个 sql 语句在 MySQL 中的执行流程,包括 sql 的查询在 MySQL 内部会怎么流转,sql 语句的更新是怎么完成的. 在分析之前我会先带着你看看 MySQL 的基础架构, ...

  5. Python中变量的命名

    变量的命名 目标 标识符和关键字 变量的命名规则 0.1 标识符和关键字 1.1 标识符 标示符就是程序员定义的 变量名.函数名 名字 需要有 见名知义 的效果,见下图: 标示符可以由 字母.下划线 ...

  6. Android布局中的空格以及占一个汉字宽度的空格,实现不同汉字字数对齐

    前言 在Android布局中进行使用到空格,以便实现文字的对齐.那么在Android中如何表示一个空格呢? 空格: (普通的英文半角空格但不换行) 窄空格:   (中文全角空格 (一个中文宽度))   ...

  7. 用dos命令导出一个文件夹里面所有文件的名字(装逼利器)

    首先,当然是在相关的文件夹打开dos命令窗口. 然后,输入如下命令:dir/b >a.txt 如果你非常了解dos命令,那么你一定会觉得这个东西简单到爆,而且我的理解和猜想都有些无知. 但如果你 ...

  8. 知其然而所以然:Operating System 概述和学习图

    大神绕道,鄙人初入 OS . 一.想知OS,先知计算机系统概述 #图解 #基本指令和中断周期 #直接内存存取(Direct Memory Access,DMA) I/O模块对存储器发出读命令或者写命令 ...

  9. 通用Web后台魔方NewLife.Cube

    魔方 是一个基于 ASP.NET MVC 的 用户权限管理平台,可作为各种信息管理系统的基础框架. 演示:http://cube.newlifex.com 源码 源码: http://git.newl ...

  10. VC连接MySql

    VC连接MySql 一丶MySql 需要了解的知识 VC连接MySql 需要了解几个关键的API: MYSQL * stdcall mysql init (MYSQL *mysql):  初始化一个数 ...