【博弈论】【SG函数】【枚举】bzoj1188 [HNOI2007]分裂游戏

因为第i个瓶子里的所有豆子都是等价的,设sg(i)表示第i个瓶子的sg值,可以转移到sg(j)^sg(k)(i<j<n,j<=k<n)的状态。

只需要考虑豆子数是奇数的瓶子啦,因为如果豆子数是偶数,重复异或是没有意义的。

对于方案数什么的……枚举就好了。

#include<cstdio>
#include<cstring>
#include<set>
using namespace std;
int T,n,a[21],SG[21];
int sg(int x)
{
	if(SG[x]!=-1) return SG[x];
	set<int>S;
	for(int i=x+1;i<n;++i)
	  for(int j=i;j<n;++j)
	    S.insert(sg(i)^sg(j));
	for(int i=0;;++i)
	  if(S.find(i)==S.end())
	    return SG[x]=i;
}
int main()
{
	scanf("%d",&T);
	for(;T;--T)
	  {
		memset(SG,-1,sizeof(SG));
	  	int ans=0,sum=0;
	  	scanf("%d",&n);
	  	for(int i=0;i<n;++i)
	  	  {
	  	  	scanf("%d",&a[i]);
	  	  	if(a[i]&1) ans^=sg(i);
	  	  }
	  	if(ans)
	  	  {
	  	  	for(int i=0;i<n;++i) if(a[i])
	  	  	  for(int j=i+1;j<n;++j)
	  	  	    for(int k=j;k<n;++k)
	  	  	      {
	  	  	      	--a[i];
	  	  	      	++a[j];
	  	  	      	++a[k];
	  	  	      	int t=0;
					for(int l=0;l<n;++l)
	  	  	      	  if(a[l]&1)
	  	  	      	    t^=sg(l);
	  	  	      	if(!t)
	  	  	      	  {
	  	  	      	  	++sum;
	  	  	      	  	if(sum==1)
	  	  	      	  	  printf("%d %d %d\n",i,j,k);
	  	  	      	  }
	  	  	      	++a[i];
	  	  	      	--a[j];
	  	  	      	--a[k];
	  	  	      }
	  	  	printf("%d\n",sum);
	  	  }
	  	else printf("-1 -1 -1\n0\n");
	  }
	return 0;
}
时间: 2024-12-30 03:57:20

【博弈论】【SG函数】【枚举】bzoj1188 [HNOI2007]分裂游戏的相关文章

Bzoj1188 [HNOI2007]分裂游戏

Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1110  Solved: 679 Description 聪聪和睿睿最近迷上了一款叫做分裂的游戏. 该游戏的规则试: 共有 n 个瓶子, 标号为 0,1,2.....n-1, 第 i 个瓶子中装有 p[i]颗巧克力豆,两个人轮流取豆子,每一轮每人选择 3 个瓶子.标号为 i,j,k, 并要保证 i < j , j < = k 且第 i 个瓶子中至少要有 1 颗巧克力豆,随后这个人从第 i 个瓶子中

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

1188: [HNOI2007]分裂游戏 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 733  Solved: 451[Submit][Status][Discuss] Description 聪 聪和睿睿最近迷上了一款叫做分裂的游戏. 该游戏的规则试: 共有 n 个瓶子, 标号为 0,1,2.....n-1, 第 i 个瓶子中装有 p[i]颗巧克力豆,两个人轮流取豆子,每一轮每人选择 3 个瓶子.标号为 i,j,k, 并要保证 i < j ,

BZOJ P1188 HNOI2007 分裂游戏——solution

题目描述: (<--这个) 组合游戏,——把每个石头看做一个游戏, Multi_game——消去i上的石子后,,k上的游戏又多了一个: 于是就套用multi_game的模型即可 求解SG函数时,发现一个游戏的后继是谁只与其位置有关,于是可以用一个SG值代替一堆游戏的SG值: 求解完所有SG值,后异或即可: 代码: 1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 int a[25],n,sg[25]

Nim or not Nim?(hdu3032+SG函数)取走-分割游戏,经典

小k,终于忍不住了...正在笔记本上装win10,有点小激动. Nim or not Nim? Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 3032 Description Nim is a two-player mathematic game of strategy in which players take turns remov

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

题目链接:BZOJ - 1188 题目分析 我们把每一颗石子看做一个单个的游戏,它的 SG 值取决于它的位置. 对于一颗在 i 位置的石子,根据游戏规则,它的后继状态就是枚举符合条件的 j, k.然后后继状态就是 j 与 k 这两个游戏的和. 游戏的和的 SG 值就是几个单一游戏的 SG 值的异或和. 那么还是根据 SG 函数的定义 , 即 SG(u) = mex(SG(v)) ,预处理求出每个位置的 SG 值.一个位置的 SG 值与它后面的位置有关,是取决于它是倒数第几个位置,那么我们预处理求

[BZOJ 1874] [BeiJing2009 WinterCamp] 取石子游戏 【博弈论 | SG函数】

题目链接:BZOJ - 1874 题目分析 这个是一种组合游戏,是许多单个SG游戏的和. 就是指,总的游戏由许多单个SG游戏组合而成,每个SG游戏(也就是每一堆石子)之间互不干扰,每次从所有的单个游戏中选一个进行决策,如果所有单个游戏都无法决策,游戏失败. 有一个结论,SG(A + B + C ... ) = SG(A)^SG(B)^SG(C) ... 这道题每堆石子不超过 1000 , 所以可以把 [0, 1000] 的 SG 值暴力求出来,使用最原始的 SG 函数的定义, SG(u) = m

BZOJ 1188: [HNOI2007]分裂游戏(multi-nim)

Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 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个瓶子中拿走

2016多校联合训练1 B题Chess (博弈论 SG函数)

题目大意:一个n(n<=1000)行,20列的棋盘上有一些棋子,两个人下棋,每回合可以把任意一个棋子向右移动到这一行的离这个棋子最近的空格上(注意这里不一定是移动最后一个棋子),不能移动到棋盘外,不能移动了就算输,两个人都用最优策略,问先手是否有必胜策略. 这题显然就是SG函数了吧.行与行之间互不影响,所以可以看成n个子游戏,求出它们各自的SG函数然后异或一下就可以了.我们发现只有20列,2^21=2097152,所以我们可以先把行的所有情况的SG函数预处理出来,然后每次询问O(1)就行了. 代

POJ 2425 A Chess Game 博弈论 sg函数

http://poj.org/problem?id=2425 典型的sg函数,建图搜sg函数预处理之后直接求每次游戏的异或和.仍然是因为看不懂题目卡了好久. 这道题大概有两个坑, 1.是搜索的时候vis数组应该在函数内声明(似乎这是我经常在搜索里犯的错误,为了省一点空间整道题都写错了): 2.是n个点的有向无环图边数上限是n^2(re了好久QAQ). 在漫长的查资料过程之后终于大概搞懂了sg函数的原理,愉快.下一篇大概会写一个小结. 代码 1 #include<cstdio> 2 #inclu