sg

sg函数模板

浪子不回头ぞ 提交于 2019-12-01 08:11:41
hdu1536: Arthur and his sister Caroll have been playing a game called Nim for some time now. Nim is played as follows: The starting position has a number of heaps, all containing some, not necessarily equal, number of beads. The players take turns chosing a heap and removing a positive number of beads from it. The first player not able to make a move, loses. Arthur and Caroll really enjoyed playing this simple game until they recently learned an easy way to always be able to find the best move: Xor the number of beads in the heaps in the current position (i.e. if we have 2, 4 and 7 the xor-sum

POJ 2960 S-Nim(SG函数模板题)

情到浓时终转凉″ 提交于 2019-12-01 06:09:52
链接: https://vjudge.net/problem/POJ-2960 题意:每行输入首先给出一个数k,代表集合S的大小,接下来紧跟着k个数,表示集合S里的数。接下来一行数为m代表有m个游戏,后面m行每行第一个数字为n代表有n堆石子,后面紧跟着n个数代表每堆石子的个数。多组数据,做到0结束    对于每组数据,我们要输出n个字母,第i个字母为“W”代表第i个游戏先手必胜,“L”代表第i个游戏先手必败,做完一组数据后换行。 题解:模板题 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; // sg值的计算方法: //1.可选步数为1~m的连续整数,直接取模即可,SG(x) = x % (m+1);‘ //2.可选步数为任意步,SG(x) = x //3.可选步数为一系列不连续的数,用打表或者dfs计算 const int maxn=105, maxm=10005; int S[maxn], sg[maxm], vis[maxm]; int n, m, size; void get_sg() { memset(sg, 0, sizeof(sg)); for(int i=1; i<=maxm; i++) { memset(vis, 0, sizeof(vis)); for

51Nod - 1714 B君的游戏

给你一囗甜甜゛ 提交于 2019-11-30 23:10:12
每个数的SG值之和他有多少个1相关 打表复杂度:找K个有序的<n的非负数的复杂度为n k /(k!) 则这题的SG打表复杂度为64 8 /7! 为1e10左右 void dfs(int cur, int yu, int ans, int next) { if(yu==0) { vis[ans]=1; return ; } for(int i=next; i<cur; i++) dfs(cur, yu-1, ans^sg[i], i); } void init() { sg[0]=0; for(int i=1;i<=64; i++) { memset(vis,0,sizeof(vis)); dfs(i, 7, 0, 0); for(int j=0;;j++) if(!vis[j]) { sg[i]=j; break; } printf("%d\n", sg[i]); } } #include <bits/stdc++.h> using namespace std; typedef unsigned long long uLL; int sg[] = {0, 1, 2, 4, 8, 16, 32, 64, 128, 255, 256, 512, 1024, 2048, 3855, 4096, 8192, 13107, 16384, 21845, 27306, 32768, 38506,

P3185 [HNOI2007]分裂游戏

二次信任 提交于 2019-11-28 19:19:10
传送门 因为每个豆子都是互相独立的,所以各看成一个子博弈 他们之间的状态只和位置有关,因为每次操作都会多出一个豆子,相当于多一个子博弈 那就是 $multi-SG$ 模型了,数据很小,考虑直接求出每个状态的 $SG$ 值 根据 $multi-SG$ 的理论,设 $SG[i]$ 表示第 $i$ 个位置的 $SG$,那么有 $SG[i]=mex(SG[j]\ xor\ SG[k]),i<j<=k<=n$ 然后枚举第一步怎么走,看看走完后总的 $SG$ 是不是 $0$ 就知道后手是不是必败了 当然如果把位置倒过来求 $SG$,就只要预处理一次 $SG$,因为那样 $SG$ 就与 $n$ 无关了 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch

SG函数总结

こ雲淡風輕ζ 提交于 2019-11-28 07:53:53
首先定义 \(mex\) (minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。例如 \(mex\{0,1,2,4\}=3\) 、 \(mex\{2,3,5\}=0\) 、 \(mex\{\}=0\) 。 对于任意状态 \(x\) ,定义 \(SG(x) = mex(F)\) ,其中 \(F\) 是 \(x\) 后继状态的 \(SG\) 函数值的集合(就是上述 \(mex\) 中的数值)。例如 \(x\) 有三个后继状态分别为 \(SG(a)\) 、 \(SG(b)\) 、 \(SG(c)\) ,那么 \(SG(x) = mex\{SG(a),SG(b),SG(c)\}\) 。当且仅当 \(x\) 为必败点时, \(SG(x)=0\) 。 游戏和的 \(SG\) 函数等于各个游戏 \(SG\) 函数的 \(Nim\) 和。 来源: https://www.cnblogs.com/solvit/p/11400417.html

hdu1536 S-Nim 博弈sg模板题 两种写法(递归+!递归)

冷暖自知 提交于 2019-11-27 15:45:52
LINK 题目描述 给定n堆石子以及一个由k个不同正整数构成的数字集合S。 现在有两位玩家轮流操作,每次操作可以从任意一堆石子中拿取石子,每次拿取的石子数量必须包含于集合S,最后无法进行操作的人视为失败。 问如果两人都采用最优策略,先手是否必胜。 数据范围 1≤n,k≤100, 1≤si,hi≤10000 样例 2 2 5 1 3 2 4 7 输出 W 定理1:对于集合S,mex(S)=mex({x1,x2…})=S中 没有出现的 最小非负整数 定理2.1:sg(n)=mex({sg(i1),sg(i2),sg(i3)…})。 n为结点;i1,i2,i3…是n的后继结点 定理2.2:sg(G)=sg(head). G是一个有向图,head是G的头结点。 定理3:sg(G1) sg(G2) sg(G3) … sg(Gn)为n个有向图的异或和,对于n个有向图游戏,这个异或和就是它的答案(和nim类似,这个定理感兴趣可以去证明) 算法1:递归 C++ 代码 # include <bits/stdc++.h> using namespace std ; int s [ 110 ] , k , m , l , x , sg [ 11000 ] , ans ; //这个题目的有向图可以看成一个树,叶子结点就是必败结点值为0。非叶子结点存放mex({子节点的值})。 int sg_dfs (

bzoj 2688

こ雲淡風輕ζ 提交于 2019-11-27 09:32:29
卡特兰数+博弈论+dp 树上删边游戏的公式是一个节点的$sg$值为儿子节点$sg$值$+1$的异或和。 设$dp_{i,j}$表示$i$个节点的二叉树$sg$值为$j$的概率,二叉树个数为卡特兰数,转移即可。 整个游戏的$sg$值等于每棵二叉树的$sg$值异或和。 设$g_{i.j}$为前i棵二叉树$sg$值为$j$的方案数,转移即可,答案为$1-g_{n,0}$。 复杂度$O(n^4)$ #include <bits/stdc++.h> using namespace std; const int maxn = 155, m = 128; int n; int A[maxn]; double h[maxn], dp[maxn][maxn], f[maxn][maxn]; int main() { h[0] = 1; for(int i = 1; i < m; ++i) for(int j = 0; j < i; ++j) h[i] += h[j] * h[i - j - 1]; scanf("%d", &n); for(int i = 1; i <= n; ++i) scanf("%d", &A[i]); dp[1][0] = 1; for(int i = 2; i <= n; ++i) { for(int j = 0; j < m; ++j) dp[i][j + 1] += 2

Game on Plane(博弈 SG)

百般思念 提交于 2019-11-26 19:51:49
You are given N N points on a plane. These points are precisely the set of vertices of some regular N N-gon. Koosaga, an extreme villain, is challenging you with a game using these points. You and Koosaga alternatively take turns, and in each turn, the player chooses two of the given points, then draws the line segment connecting the two chosen points. Also, the newly drawn line segment must not intersect with any of the previously drawn line segments in the interior. It is possible for two segments to meet at their endpoints. If at any point of the game, there exists a convex polygon

sg函数理解

落爺英雄遲暮 提交于 2019-11-26 12:40:06
首先理解sg函数必须先理解mex函数 mex是求除它集合内的最小大于等于0的整数,例:mex{1,2}=0;mex{2}=0;mex{0,1,2}=3;mex{0,5}=1。 而sg函数是啥呢? 对于任意状态 x , 定义 sg(x) = mex(f),其中f 是 x 后继状态的sg函数值的集合(就是上述mex中的数值)。最后返回值(也就是sg(x))为0为必败点,不为零必胜点。 看不懂,咱直接来个例子: 例如:取石子问题,有1堆n个的石子,每次只能取{1,3,4}个石子,先取完石子者胜利,那么各个数的SG值为多少? sg[0]=0,f[]={1,3,4}, x=1时,可以取走1-f{1}个石子,剩余{0}个,mex{sg[0]}={0},故sg[1]=1; x=2时,可以取走2-f{1}个石子,剩余{1}个,mex{sg[1]}={1},故sg[2]=0; x=3时,可以取走3-f{1,3}个石子,剩余{2,0}个,mex{sg[2],sg[0]}={0,0},故sg[3]=1; x=4时,可以取走4-f{1,3,4}个石子,剩余{3,1,0}个,mex{sg[3],sg[1],sg[0]}={1,1,0},故sg[4]=2; x=5时,可以取走5-f{1,3,4}个石子,剩余{4,2,1}个,mex{sg[4],sg[2],sg[1]}={2,0,1},故sg[5]=3;